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/socket.h>
23 #include <sys/types.h>
35 #include "got_error.h"
36 #include "got_cancel.h"
37 #include "got_object.h"
38 #include "got_opentemp.h"
40 #include "got_reference.h"
41 #include "got_repository.h"
42 #include "got_repository_load.h"
44 #include "got_lib_delta.h"
45 #include "got_lib_hash.h"
46 #include "got_lib_object.h"
47 #include "got_lib_object_cache.h"
48 #include "got_lib_pack.h"
49 #include "got_lib_ratelimit.h"
50 #include "got_lib_repository.h"
51 #include "got_lib_privsep.h"
53 #define GIT_BUNDLE_SIGNATURE_V2 "# v2 git bundle\n"
56 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
60 #define ssizeof(_x) ((ssize_t)(sizeof(_x)))
63 static const struct got_error
*
64 temp_file(int *fd
, char **path
, const char *ext
, struct got_repository
*repo
)
66 const struct got_error
*err
;
72 r
= snprintf(p
, sizeof(p
), "%s/%s/loading",
73 got_repo_get_path_git_dir(repo
), GOT_OBJECTS_PACK_DIR
);
74 if (r
< 0 || (size_t)r
>= sizeof(p
))
75 return got_error_from_errno("snprintf");
77 err
= got_opentemp_named_fd(path
, fd
, p
, ext
);
81 if (fchmod(*fd
, GOT_DEFAULT_FILE_MODE
) == -1)
82 return got_error_from_errno("fchmod");
87 static const struct got_error
*
88 load_report_progress(got_load_progress_cb progress_cb
, void *progress_arg
,
89 struct got_ratelimit
*rl
, off_t packsiz
, int nobj_total
,
90 int nobj_indexed
, int nobj_loose
, int nobj_resolved
)
92 const struct got_error
*err
;
95 if (progress_cb
== NULL
)
98 err
= got_ratelimit_check(&elapsed
, rl
);
102 return progress_cb(progress_arg
, packsiz
, nobj_total
, nobj_indexed
,
103 nobj_loose
, nobj_resolved
);
106 static const struct got_error
*
107 copypack(FILE *in
, int outfd
, off_t
*tot
,
108 struct got_object_id
*id
, struct got_ratelimit
*rl
,
109 got_load_progress_cb progress_cb
, void *progress_arg
,
110 got_cancel_cb cancel_cb
, void *cancel_arg
)
112 const struct got_error
*err
;
113 struct got_hash hash
;
114 struct got_object_id expected_id
;
115 char buf
[BUFSIZ
], sha1buf
[SHA1_DIGEST_LENGTH
];
116 size_t r
, sha1buflen
= 0;
119 got_hash_init(&hash
, GOT_HASH_SHA1
);
122 err
= cancel_cb(cancel_arg
);
126 r
= fread(buf
, 1, sizeof(buf
), in
);
131 * An expected SHA1 checksum sits at the end of the
132 * pack file. Since we don't know the file size ahead
133 * of time we have to keep SHA1_DIGEST_LENGTH bytes
134 * buffered and avoid mixing those bytes int our hash
135 * computation until we know for sure that additional
136 * pack file data bytes follow.
138 * We can assume that BUFSIZE is greater than
139 * SHA1_DIGEST_LENGTH and that a short read means that
143 if (r
>= sizeof(sha1buf
)) {
145 got_hash_update(&hash
, sha1buf
, sha1buflen
);
146 if (write(outfd
, sha1buf
, sha1buflen
) == -1)
147 return got_error_from_errno("write");
149 r
-= sizeof(sha1buf
);
150 memcpy(sha1buf
, &buf
[r
], sizeof(sha1buf
));
151 sha1buflen
= sizeof(sha1buf
);
154 got_hash_update(&hash
, buf
, r
);
155 if (write(outfd
, buf
, r
) == -1)
156 return got_error_from_errno("write");
158 err
= load_report_progress(progress_cb
, progress_arg
,
159 rl
, *tot
, 0, 0, 0, 0);
167 return got_error(GOT_ERR_BAD_PACKFILE
);
169 /* short read, we've reached EOF */
171 got_hash_update(&hash
, sha1buf
, r
);
172 if (write(outfd
, sha1buf
, r
) == -1)
173 return got_error_from_errno("write");
175 memmove(&sha1buf
[0], &sha1buf
[r
], sizeof(sha1buf
) - r
);
176 memcpy(&sha1buf
[sizeof(sha1buf
) - r
], buf
, r
);
181 return got_error(GOT_ERR_BAD_PACKFILE
);
183 got_hash_final_object_id(&hash
, id
);
186 memset(&expected_id
, 0, sizeof(expected_id
));
187 memcpy(&expected_id
.sha1
, sha1buf
, sizeof(expected_id
.sha1
));
189 if (got_object_id_cmp(id
, &expected_id
) != 0)
190 return got_error(GOT_ERR_PACKIDX_CSUM
);
192 /* re-add the expected hash at the end of the pack */
193 if (write(outfd
, sha1buf
, sizeof(sha1buf
)) == -1)
194 return got_error_from_errno("write");
196 *tot
+= sizeof(sha1buf
);
197 err
= progress_cb(progress_arg
, *tot
, 0, 0, 0, 0);
204 const struct got_error
*
205 got_repo_load(FILE *in
, struct got_pathlist_head
*refs_found
,
206 struct got_repository
*repo
, int list_refs_only
, int noop
,
207 got_load_progress_cb progress_cb
, void *progress_arg
,
208 got_cancel_cb cancel_cb
, void *cancel_arg
)
210 const struct got_error
*err
= NULL
;
211 struct got_object_id id
;
212 struct got_object
*obj
;
213 struct got_packfile_hdr pack_hdr
;
214 struct got_ratelimit rl
;
215 struct imsgbuf idxibuf
;
216 const char *repo_path
;
217 char *packpath
= NULL
, *idxpath
= NULL
;
218 char *tmppackpath
= NULL
, *tmpidxpath
= NULL
;
219 int packfd
= -1, idxfd
= -1;
220 char *spc
, *refname
, *id_str
= NULL
;
227 int tmpfds
[3] = {-1, -1, -1};
228 int imsg_idxfds
[2] = {-1, -1};
229 int ch
, done
, nobj
, idxstatus
;
232 got_ratelimit_init(&rl
, 0, 500);
234 repo_path
= got_repo_get_path_git_dir(repo
);
236 linelen
= getline(&line
, &linesize
, in
);
238 err
= got_ferror(in
, GOT_ERR_IO
);
242 if (strcmp(line
, GIT_BUNDLE_SIGNATURE_V2
) != 0) {
243 err
= got_error(GOT_ERR_BUNDLE_FORMAT
);
247 /* Parse the prerequisite */
256 linelen
= getline(&line
, &linesize
, in
);
258 err
= got_ferror(in
, GOT_ERR_IO
);
262 if (line
[linelen
- 1] == '\n')
263 line
[linelen
- 1] = '\0';
265 if (!got_parse_object_id(&id
, line
, GOT_HASH_SHA1
)) {
266 err
= got_error_path(line
, GOT_ERR_BAD_OBJ_ID_STR
);
270 err
= got_object_open(&obj
, repo
, &id
);
273 got_object_close(obj
);
276 /* Read references */
278 struct got_object_id
*id
;
281 linelen
= getline(&line
, &linesize
, in
);
283 err
= got_ferror(in
, GOT_ERR_IO
);
286 if (line
[linelen
- 1] == '\n')
287 line
[linelen
- 1] = '\0';
291 spc
= strchr(line
, ' ');
293 err
= got_error(GOT_ERR_IO
);
299 if (!got_ref_name_is_valid(refname
)) {
300 err
= got_error(GOT_ERR_BAD_REF_DATA
);
304 id
= malloc(sizeof(*id
));
306 err
= got_error_from_errno("malloc");
310 if (!got_parse_object_id(id
, line
, GOT_HASH_SHA1
)) {
312 err
= got_error(GOT_ERR_BAD_OBJ_ID_STR
);
316 dup
= strdup(refname
);
319 err
= got_error_from_errno("strdup");
323 err
= got_pathlist_append(refs_found
, dup
, id
);
334 err
= temp_file(&packfd
, &tmppackpath
, ".pack", repo
);
338 err
= temp_file(&idxfd
, &tmpidxpath
, ".idx", repo
);
342 err
= copypack(in
, packfd
, &packsiz
, &id
, &rl
,
343 progress_cb
, progress_arg
, cancel_cb
, cancel_arg
);
347 if (lseek(packfd
, 0, SEEK_SET
) == -1) {
348 err
= got_error_from_errno("lseek");
352 /* Safety checks on the pack' content. */
353 if (packsiz
<= ssizeof(pack_hdr
) + SHA1_DIGEST_LENGTH
) {
354 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
, "short pack file");
358 n
= read(packfd
, &pack_hdr
, ssizeof(pack_hdr
));
360 err
= got_error_from_errno("read");
363 if (n
!= ssizeof(pack_hdr
)) {
364 err
= got_error(GOT_ERR_IO
);
367 if (pack_hdr
.signature
!= htobe32(GOT_PACKFILE_SIGNATURE
)) {
368 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
369 "bad pack file signature");
372 if (pack_hdr
.version
!= htobe32(GOT_PACKFILE_VERSION
)) {
373 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
374 "bad pack file version");
377 nobj
= be32toh(pack_hdr
.nobjects
);
379 packsiz
> ssizeof(pack_hdr
) + SHA1_DIGEST_LENGTH
) {
380 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
381 "bad pack file with zero objects");
385 packsiz
<= ssizeof(pack_hdr
) + SHA1_DIGEST_LENGTH
) {
386 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
387 "empty pack file with non-zero object count");
391 /* nothing to do if there are no objects. */
395 for (i
= 0; i
< nitems(tmpfds
); i
++) {
396 tmpfds
[i
] = got_opentempfd();
397 if (tmpfds
[i
] == -1) {
398 err
= got_error_from_errno("got_opentempfd");
403 if (lseek(packfd
, 0, SEEK_SET
) == -1) {
404 err
= got_error_from_errno("lseek");
408 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_idxfds
) == -1) {
409 err
= got_error_from_errno("socketpair");
414 err
= got_error_from_errno("fork");
416 } else if (idxpid
== 0)
417 got_privsep_exec_child(imsg_idxfds
,
418 GOT_PATH_PROG_INDEX_PACK
, tmppackpath
);
419 if (close(imsg_idxfds
[1]) == -1) {
420 err
= got_error_from_errno("close");
424 imsg_init(&idxibuf
, imsg_idxfds
[0]);
426 err
= got_privsep_send_index_pack_req(&idxibuf
, id
.sha1
, packfd
);
431 err
= got_privsep_send_index_pack_outfd(&idxibuf
, idxfd
);
436 for (i
= 0; i
< nitems(tmpfds
); i
++) {
437 err
= got_privsep_send_tmpfd(&idxibuf
, tmpfds
[i
]);
445 int nobj_total
, nobj_indexed
, nobj_loose
, nobj_resolved
;
447 err
= got_privsep_recv_index_progress(&done
, &nobj_total
,
448 &nobj_indexed
, &nobj_loose
, &nobj_resolved
, &idxibuf
);
451 if (nobj_indexed
!= 0) {
452 err
= load_report_progress(progress_cb
, progress_arg
,
453 &rl
, packsiz
, nobj_total
, nobj_indexed
,
454 nobj_loose
, nobj_resolved
);
459 if (close(imsg_idxfds
[0]) == -1) {
460 err
= got_error_from_errno("close");
464 if (waitpid(idxpid
, &idxstatus
, 0) == -1) {
465 err
= got_error_from_errno("waitpid");
472 err
= got_object_id_str(&id_str
, &id
);
476 if (asprintf(&packpath
, "%s/%s/pack-%s.pack", repo_path
,
477 GOT_OBJECTS_PACK_DIR
, id_str
) == -1) {
478 err
= got_error_from_errno("asprintf");
482 if (asprintf(&idxpath
, "%s/%s/pack-%s.idx", repo_path
,
483 GOT_OBJECTS_PACK_DIR
, id_str
) == -1) {
484 err
= got_error_from_errno("asprintf");
488 if (rename(tmppackpath
, packpath
) == -1) {
489 err
= got_error_from_errno3("rename", tmppackpath
, packpath
);
495 if (rename(tmpidxpath
, idxpath
) == -1) {
496 err
= got_error_from_errno3("rename", tmpidxpath
, idxpath
);
508 if (tmppackpath
&& unlink(tmppackpath
) == -1 && err
== NULL
)
509 err
= got_error_from_errno2("unlink", tmppackpath
);
510 if (packfd
!= -1 && close(packfd
) == -1 && err
== NULL
)
511 err
= got_error_from_errno("close");
514 if (tmpidxpath
&& unlink(tmpidxpath
) == -1 && err
== NULL
)
515 err
= got_error_from_errno2("unlink", tmpidxpath
);
516 if (idxfd
!= -1 && close(idxfd
) == -1 && err
== NULL
)
517 err
= got_error_from_errno("close");
520 if (imsg_idxfds
[0] != -1 && close(imsg_idxfds
[0]) == -1 && err
== NULL
)
521 err
= got_error_from_errno("close");
522 if (imsg_idxfds
[1] != -1 && close(imsg_idxfds
[1]) == -1 && err
== NULL
)
523 err
= got_error_from_errno("close");
525 for (i
= 0; i
< nitems(tmpfds
); ++i
)
526 if (tmpfds
[i
] != -1 && close(tmpfds
[i
]) == -1 && err
== NULL
)
527 err
= got_error_from_errno("close");