2 * Copyright (c) 2019 Stefan Sperling <stsp@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/types.h>
21 #include <sys/queue.h>
35 #include "got_error.h"
36 #include "got_object.h"
37 #include "got_repository.h"
38 #include "got_opentemp.h"
42 #include "got_lib_hash.h"
43 #include "got_lib_deflate.h"
44 #include "got_lib_delta.h"
45 #include "got_lib_object.h"
46 #include "got_lib_object_parse.h"
47 #include "got_lib_lockfile.h"
49 #include "got_lib_object_create.h"
54 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
57 static const struct got_error
*
58 create_object_file(struct got_object_id
*id
, FILE *content
,
59 off_t content_len
, struct got_repository
*repo
)
61 const struct got_error
*err
= NULL
, *unlock_err
= NULL
;
62 char *objpath
= NULL
, *tmppath
= NULL
;
64 struct got_lockfile
*lf
= NULL
;
67 err
= got_object_get_path(&objpath
, id
, repo
);
71 err
= got_opentemp_named(&tmppath
, &tmpfile
, objpath
, "");
74 if (!(err
->code
== GOT_ERR_ERRNO
&& errno
== ENOENT
))
76 err
= got_path_dirname(&parent_path
, objpath
);
79 err
= got_path_mkdir(parent_path
);
83 err
= got_opentemp_named(&tmppath
, &tmpfile
, objpath
, "");
88 if (fchmod(fileno(tmpfile
), GOT_DEFAULT_FILE_MODE
) != 0) {
89 err
= got_error_from_errno2("fchmod", tmppath
);
93 err
= got_deflate_to_file(&tmplen
, content
, content_len
, tmpfile
, NULL
);
97 err
= got_lockfile_lock(&lf
, objpath
, -1);
101 if (rename(tmppath
, objpath
) != 0) {
102 err
= got_error_from_errno3("rename", tmppath
, objpath
);
110 if (unlink(tmppath
) != 0 && err
== NULL
)
111 err
= got_error_from_errno2("unlink", tmppath
);
114 if (tmpfile
&& fclose(tmpfile
) == EOF
&& err
== NULL
)
115 err
= got_error_from_errno("fclose");
117 unlock_err
= got_lockfile_unlock(lf
, -1);
118 return err
? err
: unlock_err
;
121 const struct got_error
*
122 got_object_blob_file_create(struct got_object_id
**id
, FILE **blobfile
,
123 off_t
*blobsize
, const char *ondisk_path
, struct got_repository
*repo
)
125 const struct got_error
*err
= NULL
;
130 size_t headerlen
= 0, n
;
136 got_hash_init(&ctx
, got_repo_get_object_format(repo
));
138 fd
= open(ondisk_path
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
140 if (!got_err_open_nofollow_on_symlink())
141 return got_error_from_errno2("open", ondisk_path
);
143 if (lstat(ondisk_path
, &sb
) == -1) {
144 err
= got_error_from_errno2("lstat", ondisk_path
);
147 } else if (fstat(fd
, &sb
) == -1) {
148 err
= got_error_from_errno2("fstat", ondisk_path
);
152 if (asprintf(&header
, "%s %lld", GOT_OBJ_LABEL_BLOB
,
153 (long long)sb
.st_size
) == -1) {
154 err
= got_error_from_errno("asprintf");
157 headerlen
= strlen(header
) + 1;
158 got_hash_update(&ctx
, header
, headerlen
);
160 *blobfile
= got_opentemp();
161 if (*blobfile
== NULL
) {
162 err
= got_error_from_errno("got_opentemp");
166 n
= fwrite(header
, 1, headerlen
, *blobfile
);
167 if (n
!= headerlen
) {
168 err
= got_ferror(*blobfile
, GOT_ERR_IO
);
171 *blobsize
+= headerlen
;
173 char buf
[PATH_MAX
* 8];
176 if (S_ISLNK(sb
.st_mode
)) {
177 inlen
= readlink(ondisk_path
, buf
, sizeof(buf
));
179 err
= got_error_from_errno("readlink");
183 inlen
= read(fd
, buf
, sizeof(buf
));
185 err
= got_error_from_errno("read");
191 got_hash_update(&ctx
, buf
, inlen
);
192 n
= fwrite(buf
, 1, inlen
, *blobfile
);
194 err
= got_ferror(*blobfile
, GOT_ERR_IO
);
198 if (S_ISLNK(sb
.st_mode
))
202 *id
= calloc(1, sizeof(**id
));
204 err
= got_error_from_errno("calloc");
207 got_hash_final_object_id(&ctx
, *id
);
209 if (fflush(*blobfile
) != 0) {
210 err
= got_error_from_errno("fflush");
216 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
217 err
= got_error_from_errno("close");
229 const struct got_error
*
230 got_object_blob_create(struct got_object_id
**id
, const char *ondisk_path
,
231 struct got_repository
*repo
)
233 const struct got_error
*err
= NULL
;
234 FILE *blobfile
= NULL
;
237 err
= got_object_blob_file_create(id
, &blobfile
, &blobsize
,
242 err
= create_object_file(*id
, blobfile
, blobsize
, repo
);
243 if (fclose(blobfile
) == EOF
&& err
== NULL
)
244 err
= got_error_from_errno("fclose");
252 static const struct got_error
*
253 te_mode2str(char *buf
, size_t len
, struct got_tree_entry
*te
)
259 * Some Git implementations are picky about modes seen in tree entries.
260 * For best compatibility we normalize the file/directory mode here.
262 if (S_ISREG(te
->mode
)) {
263 mode
= GOT_DEFAULT_FILE_MODE
;
264 if (te
->mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))
265 mode
|= S_IXUSR
| S_IXGRP
| S_IXOTH
;
266 } else if (got_object_tree_entry_is_submodule(te
))
267 mode
= S_IFDIR
| S_IFLNK
;
268 else if (S_ISLNK(te
->mode
))
269 mode
= S_IFLNK
; /* Git leaves all the other bits unset. */
270 else if (S_ISDIR(te
->mode
))
271 mode
= S_IFDIR
; /* Git leaves all the other bits unset. */
273 return got_error(GOT_ERR_BAD_FILETYPE
);
275 ret
= snprintf(buf
, len
, "%o ", mode
);
276 if (ret
< 0 || (size_t)ret
>= len
)
277 return got_error(GOT_ERR_NO_SPACE
);
282 * Git expects directory tree entries to be sorted with an imaginary slash
283 * appended to their name, and will break otherwise. Let's be nice.
284 * This function is intended to be used with mergesort(3) to sort an
285 * array of pointers to struct got_tree_entry objects.
288 sort_tree_entries_the_way_git_likes_it(const void *arg1
, const void *arg2
)
290 struct got_tree_entry
* const *te1
= arg1
;
291 struct got_tree_entry
* const *te2
= arg2
;
292 char name1
[NAME_MAX
+ 2];
293 char name2
[NAME_MAX
+ 2];
295 strlcpy(name1
, (*te1
)->name
, sizeof(name1
));
296 strlcpy(name2
, (*te2
)->name
, sizeof(name2
));
297 if (S_ISDIR((*te1
)->mode
))
298 strlcat(name1
, "/", sizeof(name1
));
299 if (S_ISDIR((*te2
)->mode
))
300 strlcat(name2
, "/", sizeof(name2
));
301 return strcmp(name1
, name2
);
304 const struct got_error
*
305 got_object_tree_create(struct got_object_id
**id
,
306 struct got_pathlist_head
*paths
, int nentries
, struct got_repository
*repo
)
308 const struct got_error
*err
= NULL
;
309 char modebuf
[sizeof("100644 ")];
312 size_t headerlen
, len
= 0, n
, digest_len
;
313 FILE *treefile
= NULL
;
315 struct got_pathlist_entry
*pe
;
316 struct got_tree_entry
**sorted_entries
;
317 struct got_tree_entry
*te
;
318 enum got_hash_algorithm algo
;
323 algo
= got_repo_get_object_format(repo
);
324 digest_len
= got_hash_digest_length(algo
);
325 got_hash_init(&ctx
, algo
);
327 sorted_entries
= calloc(nentries
, sizeof(struct got_tree_entry
*));
328 if (sorted_entries
== NULL
)
329 return got_error_from_errno("calloc");
332 RB_FOREACH(pe
, got_pathlist_head
, paths
)
333 sorted_entries
[i
++] = pe
->data
;
334 mergesort(sorted_entries
, nentries
, sizeof(struct got_tree_entry
*),
335 sort_tree_entries_the_way_git_likes_it
);
337 for (i
= 0; i
< nentries
; i
++) {
338 te
= sorted_entries
[i
];
339 err
= te_mode2str(modebuf
, sizeof(modebuf
), te
);
342 len
+= strlen(modebuf
) + strlen(te
->name
) + 1 + digest_len
;
345 if (asprintf(&header
, "%s %zd", GOT_OBJ_LABEL_TREE
, len
) == -1) {
346 err
= got_error_from_errno("asprintf");
349 headerlen
= strlen(header
) + 1;
350 got_hash_update(&ctx
, header
, headerlen
);
352 treefile
= got_opentemp();
353 if (treefile
== NULL
) {
354 err
= got_error_from_errno("got_opentemp");
358 n
= fwrite(header
, 1, headerlen
, treefile
);
359 if (n
!= headerlen
) {
360 err
= got_ferror(treefile
, GOT_ERR_IO
);
363 treesize
+= headerlen
;
365 for (i
= 0; i
< nentries
; i
++) {
366 te
= sorted_entries
[i
];
367 err
= te_mode2str(modebuf
, sizeof(modebuf
), te
);
370 len
= strlen(modebuf
);
371 n
= fwrite(modebuf
, 1, len
, treefile
);
373 err
= got_ferror(treefile
, GOT_ERR_IO
);
376 got_hash_update(&ctx
, modebuf
, len
);
379 len
= strlen(te
->name
) + 1; /* must include NUL */
380 n
= fwrite(te
->name
, 1, len
, treefile
);
382 err
= got_ferror(treefile
, GOT_ERR_IO
);
385 got_hash_update(&ctx
, te
->name
, len
);
389 n
= fwrite(te
->id
.hash
, 1, len
, treefile
);
391 err
= got_ferror(treefile
, GOT_ERR_IO
);
394 got_hash_update(&ctx
, te
->id
.hash
, len
);
398 *id
= calloc(1, sizeof(**id
));
400 err
= got_error_from_errno("calloc");
403 got_hash_final_object_id(&ctx
, *id
);
405 if (fflush(treefile
) != 0) {
406 err
= got_error_from_errno("fflush");
411 err
= create_object_file(*id
, treefile
, treesize
, repo
);
414 free(sorted_entries
);
415 if (treefile
&& fclose(treefile
) == EOF
&& err
== NULL
)
416 err
= got_error_from_errno("fclose");
424 const struct got_error
*
425 got_object_commit_create(struct got_object_id
**id
,
426 struct got_object_id
*tree_id
, struct got_object_id_queue
*parent_ids
,
427 int nparents
, const char *author
, time_t author_time
,
428 const char *committer
, time_t committer_time
,
429 const char *logmsg
, struct got_repository
*repo
)
431 const struct got_error
*err
= NULL
;
433 char *header
= NULL
, *tree_str
= NULL
;
434 char *author_str
= NULL
, *committer_str
= NULL
;
436 size_t headerlen
, len
= 0, n
, digest_string_len
;
437 FILE *commitfile
= NULL
;
438 off_t commitsize
= 0;
439 struct got_object_qid
*qid
;
440 enum got_hash_algorithm algo
;
445 algo
= got_repo_get_object_format(repo
);
446 digest_string_len
= got_hash_digest_string_length(algo
);
447 got_hash_init(&ctx
, algo
);
449 msg0
= strdup(logmsg
);
451 return got_error_from_errno("strdup");
454 while (isspace((unsigned char)msg
[0]))
457 while (len
> 0 && isspace((unsigned char)msg
[len
- 1])) {
462 if (asprintf(&author_str
, "%s%s %lld +0000\n",
463 GOT_COMMIT_LABEL_AUTHOR
, author
, (long long)author_time
) == -1) {
464 err
= got_error_from_errno("asprintf");
468 if (asprintf(&committer_str
, "%s%s %lld +0000\n",
469 GOT_COMMIT_LABEL_COMMITTER
, committer
? committer
: author
,
470 (long long)(committer
? committer_time
: author_time
))
472 err
= got_error_from_errno("asprintf");
476 len
= strlen(GOT_COMMIT_LABEL_TREE
) + digest_string_len
+
478 (strlen(GOT_COMMIT_LABEL_PARENT
) + digest_string_len
) +
479 + strlen(author_str
) + strlen(committer_str
) + 2 + strlen(msg
);
481 if (asprintf(&header
, "%s %zd", GOT_OBJ_LABEL_COMMIT
, len
) == -1) {
482 err
= got_error_from_errno("asprintf");
485 headerlen
= strlen(header
) + 1;
486 got_hash_update(&ctx
, header
, headerlen
);
488 commitfile
= got_opentemp();
489 if (commitfile
== NULL
) {
490 err
= got_error_from_errno("got_opentemp");
494 n
= fwrite(header
, 1, headerlen
, commitfile
);
495 if (n
!= headerlen
) {
496 err
= got_ferror(commitfile
, GOT_ERR_IO
);
499 commitsize
+= headerlen
;
501 err
= got_object_id_str(&id_str
, tree_id
);
504 if (asprintf(&tree_str
, "%s%s\n", GOT_COMMIT_LABEL_TREE
, id_str
)
506 err
= got_error_from_errno("asprintf");
509 len
= strlen(tree_str
);
510 got_hash_update(&ctx
, tree_str
, len
);
511 n
= fwrite(tree_str
, 1, len
, commitfile
);
513 err
= got_ferror(commitfile
, GOT_ERR_IO
);
521 STAILQ_FOREACH(qid
, parent_ids
, entry
) {
522 char *parent_str
= NULL
;
524 err
= got_object_id_str(&id_str
, &qid
->id
);
527 if (asprintf(&parent_str
, "%s%s\n",
528 GOT_COMMIT_LABEL_PARENT
, id_str
) == -1) {
529 err
= got_error_from_errno("asprintf");
532 len
= strlen(parent_str
);
533 got_hash_update(&ctx
, parent_str
, len
);
534 n
= fwrite(parent_str
, 1, len
, commitfile
);
536 err
= got_ferror(commitfile
, GOT_ERR_IO
);
547 len
= strlen(author_str
);
548 got_hash_update(&ctx
, author_str
, len
);
549 n
= fwrite(author_str
, 1, len
, commitfile
);
551 err
= got_ferror(commitfile
, GOT_ERR_IO
);
556 len
= strlen(committer_str
);
557 got_hash_update(&ctx
, committer_str
, len
);
558 n
= fwrite(committer_str
, 1, len
, commitfile
);
560 err
= got_ferror(commitfile
, GOT_ERR_IO
);
565 got_hash_update(&ctx
, "\n", 1);
566 n
= fwrite("\n", 1, 1, commitfile
);
568 err
= got_ferror(commitfile
, GOT_ERR_IO
);
574 got_hash_update(&ctx
, msg
, len
);
575 n
= fwrite(msg
, 1, len
, commitfile
);
577 err
= got_ferror(commitfile
, GOT_ERR_IO
);
582 got_hash_update(&ctx
, "\n", 1);
583 n
= fwrite("\n", 1, 1, commitfile
);
585 err
= got_ferror(commitfile
, GOT_ERR_IO
);
590 *id
= calloc(1, sizeof(**id
));
592 err
= got_error_from_errno("calloc");
595 got_hash_final_object_id(&ctx
, *id
);
597 if (fflush(commitfile
) != 0) {
598 err
= got_error_from_errno("fflush");
603 err
= create_object_file(*id
, commitfile
, commitsize
, repo
);
611 if (commitfile
&& fclose(commitfile
) == EOF
&& err
== NULL
)
612 err
= got_error_from_errno("fclose");
620 const struct got_error
*
621 got_object_tag_create(struct got_object_id
**id
,
622 const char *tag_name
, struct got_object_id
*object_id
, const char *tagger
,
623 time_t tagger_time
, const char *tagmsg
, const char *signer_id
,
624 struct got_repository
*repo
, int verbosity
)
626 const struct got_error
*err
= NULL
;
629 char *tag_str
= NULL
, *tagger_str
= NULL
;
630 char *id_str
= NULL
, *obj_str
= NULL
, *type_str
= NULL
;
631 size_t headerlen
, len
= 0, sig_len
= 0, n
;
632 FILE *tagfile
= NULL
;
634 char *msg0
= NULL
, *msg
;
635 const char *obj_type_str
;
641 got_hash_init(&ctx
, got_repo_get_object_format(repo
));
643 err
= got_object_id_str(&id_str
, object_id
);
646 if (asprintf(&obj_str
, "%s%s\n", GOT_TAG_LABEL_OBJECT
, id_str
) == -1) {
647 err
= got_error_from_errno("asprintf");
651 err
= got_object_get_type(&obj_type
, repo
, object_id
);
656 case GOT_OBJ_TYPE_BLOB
:
657 obj_type_str
= GOT_OBJ_LABEL_BLOB
;
659 case GOT_OBJ_TYPE_TREE
:
660 obj_type_str
= GOT_OBJ_LABEL_TREE
;
662 case GOT_OBJ_TYPE_COMMIT
:
663 obj_type_str
= GOT_OBJ_LABEL_COMMIT
;
665 case GOT_OBJ_TYPE_TAG
:
666 obj_type_str
= GOT_OBJ_LABEL_TAG
;
669 err
= got_error(GOT_ERR_OBJ_TYPE
);
673 if (asprintf(&type_str
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
674 obj_type_str
) == -1) {
675 err
= got_error_from_errno("asprintf");
679 if (asprintf(&tag_str
, "%s%s\n", GOT_TAG_LABEL_TAG
, tag_name
) == -1) {
680 err
= got_error_from_errno("asprintf");
684 if (asprintf(&tagger_str
, "%s%s %lld +0000\n",
685 GOT_TAG_LABEL_TAGGER
, tagger
, (long long)tagger_time
) == -1)
686 return got_error_from_errno("asprintf");
688 msg0
= strdup(tagmsg
);
690 err
= got_error_from_errno("strdup");
695 while (isspace((unsigned char)msg
[0]))
704 err
= buf_alloc(&buf
, 0);
709 err
= buf_puts(&len
, buf
, obj_str
);
712 err
= buf_puts(&len
, buf
, type_str
);
715 err
= buf_puts(&len
, buf
, tag_str
);
718 err
= buf_puts(&len
, buf
, tagger_str
);
721 err
= buf_putc(buf
, '\n');
724 err
= buf_puts(&len
, buf
, msg
);
727 err
= buf_putc(buf
, '\n');
731 err
= got_sigs_sign_tag_ssh(&pid
, &in_fd
, &out_fd
, signer_id
,
735 if (buf_write_fd(buf
, in_fd
) == -1) {
736 err
= got_error_from_errno("write");
739 if (close(in_fd
) == -1) {
740 err
= got_error_from_errno("close");
744 if (waitpid(pid
, &status
, 0) == -1) {
745 err
= got_error_from_errno("waitpid");
748 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0) {
749 err
= got_error(GOT_ERR_SIGNING_TAG
);
754 err
= buf_load_fd(&buf
, out_fd
);
757 sig_len
= buf_len(buf
);
758 if (close(out_fd
) == -1) {
759 err
= got_error_from_errno("close");
764 len
= strlen(obj_str
) + strlen(type_str
) + strlen(tag_str
) +
765 strlen(tagger_str
) + 1 + strlen(msg
) + 1 + sig_len
;
766 if (asprintf(&header
, "%s %zd", GOT_OBJ_LABEL_TAG
, len
) == -1) {
767 err
= got_error_from_errno("asprintf");
771 headerlen
= strlen(header
) + 1;
772 got_hash_update(&ctx
, header
, headerlen
);
774 tagfile
= got_opentemp();
775 if (tagfile
== NULL
) {
776 err
= got_error_from_errno("got_opentemp");
780 n
= fwrite(header
, 1, headerlen
, tagfile
);
781 if (n
!= headerlen
) {
782 err
= got_ferror(tagfile
, GOT_ERR_IO
);
785 tagsize
+= headerlen
;
786 len
= strlen(obj_str
);
787 got_hash_update(&ctx
, obj_str
, len
);
788 n
= fwrite(obj_str
, 1, len
, tagfile
);
790 err
= got_ferror(tagfile
, GOT_ERR_IO
);
794 len
= strlen(type_str
);
795 got_hash_update(&ctx
, type_str
, len
);
796 n
= fwrite(type_str
, 1, len
, tagfile
);
798 err
= got_ferror(tagfile
, GOT_ERR_IO
);
803 len
= strlen(tag_str
);
804 got_hash_update(&ctx
, tag_str
, len
);
805 n
= fwrite(tag_str
, 1, len
, tagfile
);
807 err
= got_ferror(tagfile
, GOT_ERR_IO
);
812 len
= strlen(tagger_str
);
813 got_hash_update(&ctx
, tagger_str
, len
);
814 n
= fwrite(tagger_str
, 1, len
, tagfile
);
816 err
= got_ferror(tagfile
, GOT_ERR_IO
);
821 got_hash_update(&ctx
, "\n", 1);
822 n
= fwrite("\n", 1, 1, tagfile
);
824 err
= got_ferror(tagfile
, GOT_ERR_IO
);
830 got_hash_update(&ctx
, msg
, len
);
831 n
= fwrite(msg
, 1, len
, tagfile
);
833 err
= got_ferror(tagfile
, GOT_ERR_IO
);
838 got_hash_update(&ctx
, "\n", 1);
839 n
= fwrite("\n", 1, 1, tagfile
);
841 err
= got_ferror(tagfile
, GOT_ERR_IO
);
846 if (signer_id
&& buf_len(buf
) > 0) {
848 got_hash_update(&ctx
, buf_get(buf
), len
);
849 n
= fwrite(buf_get(buf
), 1, len
, tagfile
);
851 err
= got_ferror(tagfile
, GOT_ERR_IO
);
857 *id
= calloc(1, sizeof(**id
));
859 err
= got_error_from_errno("calloc");
862 got_hash_final_object_id(&ctx
, *id
);
864 if (fflush(tagfile
) != 0) {
865 err
= got_error_from_errno("fflush");
870 err
= create_object_file(*id
, tagfile
, tagsize
, repo
);
878 if (tagfile
&& fclose(tagfile
) == EOF
&& err
== NULL
)
879 err
= got_error_from_errno("fclose");