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 <sys/types.h>
19 #include <sys/queue.h>
32 #include "got_error.h"
33 #include "got_object.h"
34 #include "got_repository.h"
35 #include "got_opentemp.h"
38 #include "got_lib_sha1.h"
39 #include "got_lib_deflate.h"
40 #include "got_lib_delta.h"
41 #include "got_lib_object.h"
42 #include "got_lib_lockfile.h"
45 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
48 static const struct got_error *
49 create_object_file(struct got_object_id *id, FILE *content,
50 struct got_repository *repo)
52 const struct got_error *err = NULL, *unlock_err = NULL;
53 char *objpath = NULL, *tmppath = NULL;
55 struct got_lockfile *lf = NULL;
58 err = got_object_get_path(&objpath, id, repo);
62 err = got_opentemp_named(&tmppath, &tmpfile, objpath);
65 if (!(err->code == GOT_ERR_ERRNO && errno == ENOENT))
67 err = got_path_dirname(&parent_path, objpath);
70 err = got_path_mkdir(parent_path);
74 err = got_opentemp_named(&tmppath, &tmpfile, objpath);
79 err = got_deflate_to_file(&tmplen, content, tmpfile);
83 err = got_lockfile_lock(&lf, objpath);
87 if (rename(tmppath, objpath) != 0) {
88 err = got_error_from_errno3("rename", tmppath, objpath);
94 if (chmod(objpath, GOT_DEFAULT_FILE_MODE) != 0) {
95 err = got_error_from_errno2("chmod", objpath);
101 if (unlink(tmppath) != 0 && err == NULL)
102 err = got_error_from_errno2("unlink", tmppath);
105 if (tmpfile && fclose(tmpfile) != 0 && err == NULL)
106 err = got_error_from_errno("fclose");
108 unlock_err = got_lockfile_unlock(lf);
109 return err ? err : unlock_err;
112 const struct got_error *
113 got_object_blob_create(struct got_object_id **id, const char *ondisk_path,
114 struct got_repository *repo)
116 const struct got_error *err = NULL;
118 FILE *blobfile = NULL;
122 size_t headerlen = 0, n;
128 fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW);
130 return got_error_from_errno2("open", ondisk_path);
132 if (fstat(fd, &sb) == -1) {
133 err = got_error_from_errno2("fstat", ondisk_path);
137 if (asprintf(&header, "%s %lld", GOT_OBJ_LABEL_BLOB,
139 err = got_error_from_errno("asprintf");
142 headerlen = strlen(header) + 1;
143 SHA1Update(&sha1_ctx, header, headerlen);
145 blobfile = got_opentemp();
146 if (blobfile == NULL) {
147 err = got_error_from_errno("got_opentemp");
151 n = fwrite(header, 1, headerlen, blobfile);
152 if (n != headerlen) {
153 err = got_ferror(blobfile, GOT_ERR_IO);
160 inlen = read(fd, buf, sizeof(buf));
162 err = got_error_from_errno("read");
167 SHA1Update(&sha1_ctx, buf, inlen);
168 n = fwrite(buf, 1, inlen, blobfile);
170 err = got_ferror(blobfile, GOT_ERR_IO);
175 *id = malloc(sizeof(**id));
177 err = got_error_from_errno("malloc");
180 SHA1Final((*id)->sha1, &sha1_ctx);
182 if (fflush(blobfile) != 0) {
183 err = got_error_from_errno("fflush");
188 err = create_object_file(*id, blobfile, repo);
191 if (fd != -1 && close(fd) != 0 && err == NULL)
192 err = got_error_from_errno("close");
193 if (blobfile && fclose(blobfile) != 0 && err == NULL)
194 err = got_error_from_errno("fclose");
202 static const struct got_error *
203 mode2str(char *buf, size_t len, mode_t mode)
206 ret = snprintf(buf, len, "%o ", mode);
207 if (ret == -1 || ret >= len)
208 return got_error(GOT_ERR_NO_SPACE);
212 const struct got_error *
213 got_object_tree_create(struct got_object_id **id,
214 struct got_tree_entries *entries, struct got_repository *repo)
216 const struct got_error *err = NULL;
217 char modebuf[sizeof("100644 ")];
220 size_t headerlen, len = 0, n;
221 FILE *treefile = NULL;
222 struct got_tree_entry *te;
228 SIMPLEQ_FOREACH(te, &entries->head, entry) {
229 err = mode2str(modebuf, sizeof(modebuf), te->mode);
232 len += strlen(modebuf) + strlen(te->name) + 1 +
236 if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_TREE, len) == -1) {
237 err = got_error_from_errno("asprintf");
240 headerlen = strlen(header) + 1;
241 SHA1Update(&sha1_ctx, header, headerlen);
243 treefile = got_opentemp();
244 if (treefile == NULL) {
245 err = got_error_from_errno("got_opentemp");
249 n = fwrite(header, 1, headerlen, treefile);
250 if (n != headerlen) {
251 err = got_ferror(treefile, GOT_ERR_IO);
255 SIMPLEQ_FOREACH(te, &entries->head, entry) {
256 err = mode2str(modebuf, sizeof(modebuf), te->mode);
259 len = strlen(modebuf);
260 n = fwrite(modebuf, 1, len, treefile);
262 err = got_ferror(treefile, GOT_ERR_IO);
265 SHA1Update(&sha1_ctx, modebuf, len);
267 len = strlen(te->name) + 1; /* must include NUL */
268 n = fwrite(te->name, 1, len, treefile);
270 err = got_ferror(treefile, GOT_ERR_IO);
273 SHA1Update(&sha1_ctx, te->name, len);
275 len = SHA1_DIGEST_LENGTH;
276 n = fwrite(te->id->sha1, 1, len, treefile);
278 err = got_ferror(treefile, GOT_ERR_IO);
281 SHA1Update(&sha1_ctx, te->id->sha1, len);
284 *id = malloc(sizeof(**id));
286 err = got_error_from_errno("malloc");
289 SHA1Final((*id)->sha1, &sha1_ctx);
291 if (fflush(treefile) != 0) {
292 err = got_error_from_errno("fflush");
297 err = create_object_file(*id, treefile, repo);
300 if (treefile && fclose(treefile) != 0 && err == NULL)
301 err = got_error_from_errno("fclose");
309 const struct got_error *
310 got_object_commit_create(struct got_object_id **id,
311 struct got_object_id *tree_id, struct got_object_id_queue *parent_ids,
312 int nparents, const char *author, time_t author_time,
313 const char *committer, time_t committer_time,
314 const char *logmsg, struct got_repository *repo)
316 const struct got_error *err = NULL;
318 char *header = NULL, *tree_str = NULL;
319 char *author_str = NULL, *committer_str = NULL;
321 size_t headerlen, len = 0, n;
322 FILE *commitfile = NULL;
323 struct got_object_qid *qid;
330 msg0 = strdup(logmsg);
332 return got_error_from_errno("strdup");
335 while (isspace((unsigned char)msg[0]))
338 while (len > 0 && isspace((unsigned char)msg[len - 1])) {
343 if (asprintf(&author_str, "%s%s %lld +0000\n",
344 GOT_COMMIT_LABEL_AUTHOR, author, author_time) == -1)
345 return got_error_from_errno("asprintf");
347 if (asprintf(&committer_str, "%s%s %lld +0000\n",
348 GOT_COMMIT_LABEL_COMMITTER, committer ? committer : author,
349 committer ? committer_time : author_time)
351 err = got_error_from_errno("asprintf");
355 len = strlen(GOT_COMMIT_LABEL_TREE) + SHA1_DIGEST_STRING_LENGTH +
357 (strlen(GOT_COMMIT_LABEL_PARENT) + SHA1_DIGEST_STRING_LENGTH) +
358 + strlen(author_str) + strlen(committer_str) + 2 + strlen(msg);
360 if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_COMMIT, len) == -1) {
361 err = got_error_from_errno("asprintf");
364 headerlen = strlen(header) + 1;
365 SHA1Update(&sha1_ctx, header, headerlen);
367 commitfile = got_opentemp();
368 if (commitfile == NULL) {
369 err = got_error_from_errno("got_opentemp");
373 n = fwrite(header, 1, headerlen, commitfile);
374 if (n != headerlen) {
375 err = got_ferror(commitfile, GOT_ERR_IO);
379 err = got_object_id_str(&id_str, tree_id);
382 if (asprintf(&tree_str, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str)
384 err = got_error_from_errno("asprintf");
387 len = strlen(tree_str);
388 SHA1Update(&sha1_ctx, tree_str, len);
389 n = fwrite(tree_str, 1, len, commitfile);
391 err = got_ferror(commitfile, GOT_ERR_IO);
396 SIMPLEQ_FOREACH(qid, parent_ids, entry) {
397 char *parent_str = NULL;
401 err = got_object_id_str(&id_str, qid->id);
404 if (asprintf(&parent_str, "%s%s\n",
405 GOT_COMMIT_LABEL_PARENT, id_str) == -1) {
406 err = got_error_from_errno("asprintf");
409 len = strlen(parent_str);
410 SHA1Update(&sha1_ctx, parent_str, len);
411 n = fwrite(parent_str, 1, len, commitfile);
413 err = got_ferror(commitfile, GOT_ERR_IO);
421 len = strlen(author_str);
422 SHA1Update(&sha1_ctx, author_str, len);
423 n = fwrite(author_str, 1, len, commitfile);
425 err = got_ferror(commitfile, GOT_ERR_IO);
429 len = strlen(committer_str);
430 SHA1Update(&sha1_ctx, committer_str, len);
431 n = fwrite(committer_str, 1, len, commitfile);
433 err = got_ferror(commitfile, GOT_ERR_IO);
437 SHA1Update(&sha1_ctx, "\n", 1);
438 n = fwrite("\n", 1, 1, commitfile);
440 err = got_ferror(commitfile, GOT_ERR_IO);
445 SHA1Update(&sha1_ctx, msg, len);
446 n = fwrite(msg, 1, len, commitfile);
448 err = got_ferror(commitfile, GOT_ERR_IO);
452 SHA1Update(&sha1_ctx, "\n", 1);
453 n = fwrite("\n", 1, 1, commitfile);
455 err = got_ferror(commitfile, GOT_ERR_IO);
459 *id = malloc(sizeof(**id));
461 err = got_error_from_errno("malloc");
464 SHA1Final((*id)->sha1, &sha1_ctx);
466 if (fflush(commitfile) != 0) {
467 err = got_error_from_errno("fflush");
472 err = create_object_file(*id, commitfile, repo);
479 if (commitfile && fclose(commitfile) != 0 && err == NULL)
480 err = got_error_from_errno("fclose");