| File: | got/../lib/object_create.c |
| Warning: | line 442, column 10 Potential leak of memory pointed to by 'msg' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (c) 2019 Stefan Sperling <stsp@openbsd.org> | |||
| 3 | * | |||
| 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. | |||
| 7 | * | |||
| 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. | |||
| 15 | */ | |||
| 16 | ||||
| 17 | #include <sys/types.h> | |||
| 18 | #include <sys/stat.h> | |||
| 19 | #include <sys/queue.h> | |||
| 20 | ||||
| 21 | #include <ctype.h> | |||
| 22 | #include <errno(*__errno()).h> | |||
| 23 | #include <fcntl.h> | |||
| 24 | #include <limits.h> | |||
| 25 | #include <stdio.h> | |||
| 26 | #include <stdlib.h> | |||
| 27 | #include <string.h> | |||
| 28 | #include <stdint.h> | |||
| 29 | #include <sha1.h> | |||
| 30 | #include <unistd.h> | |||
| 31 | #include <zlib.h> | |||
| 32 | ||||
| 33 | #include "got_error.h" | |||
| 34 | #include "got_object.h" | |||
| 35 | #include "got_repository.h" | |||
| 36 | #include "got_opentemp.h" | |||
| 37 | #include "got_path.h" | |||
| 38 | ||||
| 39 | #include "got_lib_sha1.h" | |||
| 40 | #include "got_lib_deflate.h" | |||
| 41 | #include "got_lib_delta.h" | |||
| 42 | #include "got_lib_object.h" | |||
| 43 | #include "got_lib_object_parse.h" | |||
| 44 | #include "got_lib_lockfile.h" | |||
| 45 | ||||
| 46 | #ifndef nitems | |||
| 47 | #define nitems(_a)(sizeof(_a) / sizeof((_a)[0])) (sizeof(_a) / sizeof((_a)[0])) | |||
| 48 | #endif | |||
| 49 | ||||
| 50 | static const struct got_error * | |||
| 51 | create_object_file(struct got_object_id *id, FILE *content, | |||
| 52 | struct got_repository *repo) | |||
| 53 | { | |||
| 54 | const struct got_error *err = NULL((void *)0), *unlock_err = NULL((void *)0); | |||
| 55 | char *objpath = NULL((void *)0), *tmppath = NULL((void *)0); | |||
| 56 | FILE *tmpfile = NULL((void *)0); | |||
| 57 | struct got_lockfile *lf = NULL((void *)0); | |||
| 58 | size_t tmplen = 0; | |||
| 59 | ||||
| 60 | err = got_object_get_path(&objpath, id, repo); | |||
| 61 | if (err) | |||
| 62 | return err; | |||
| 63 | ||||
| 64 | err = got_opentemp_named(&tmppath, &tmpfile, objpath); | |||
| 65 | if (err) { | |||
| 66 | char *parent_path; | |||
| 67 | if (!(err->code == GOT_ERR_ERRNO1 && errno(*__errno()) == ENOENT2)) | |||
| 68 | goto done; | |||
| 69 | err = got_path_dirname(&parent_path, objpath); | |||
| 70 | if (err) | |||
| 71 | goto done; | |||
| 72 | err = got_path_mkdir(parent_path); | |||
| 73 | free(parent_path); | |||
| 74 | if (err) | |||
| 75 | goto done; | |||
| 76 | err = got_opentemp_named(&tmppath, &tmpfile, objpath); | |||
| 77 | if (err) | |||
| 78 | goto done; | |||
| 79 | } | |||
| 80 | ||||
| 81 | if (fchmod(fileno(tmpfile)(!__isthreaded ? ((tmpfile)->_file) : (fileno)(tmpfile)), GOT_DEFAULT_FILE_MODE(0100000 | 0000400|0000200 | 0000040 | 0000004)) != 0) { | |||
| 82 | err = got_error_from_errno2("fchmod", tmppath); | |||
| 83 | goto done; | |||
| 84 | } | |||
| 85 | ||||
| 86 | err = got_deflate_to_file(&tmplen, content, tmpfile, NULL((void *)0)); | |||
| 87 | if (err) | |||
| 88 | goto done; | |||
| 89 | ||||
| 90 | err = got_lockfile_lock(&lf, objpath); | |||
| 91 | if (err) | |||
| 92 | goto done; | |||
| 93 | ||||
| 94 | if (rename(tmppath, objpath) != 0) { | |||
| 95 | err = got_error_from_errno3("rename", tmppath, objpath); | |||
| 96 | goto done; | |||
| 97 | } | |||
| 98 | free(tmppath); | |||
| 99 | tmppath = NULL((void *)0); | |||
| 100 | done: | |||
| 101 | free(objpath); | |||
| 102 | if (tmppath) { | |||
| 103 | if (unlink(tmppath) != 0 && err == NULL((void *)0)) | |||
| 104 | err = got_error_from_errno2("unlink", tmppath); | |||
| 105 | free(tmppath); | |||
| 106 | } | |||
| 107 | if (tmpfile && fclose(tmpfile) == EOF(-1) && err == NULL((void *)0)) | |||
| 108 | err = got_error_from_errno("fclose"); | |||
| 109 | if (lf) | |||
| 110 | unlock_err = got_lockfile_unlock(lf); | |||
| 111 | return err ? err : unlock_err; | |||
| 112 | } | |||
| 113 | ||||
| 114 | const struct got_error * | |||
| 115 | got_object_blob_file_create(struct got_object_id **id, FILE **blobfile, | |||
| 116 | const char *ondisk_path) | |||
| 117 | { | |||
| 118 | const struct got_error *err = NULL((void *)0); | |||
| 119 | char *header = NULL((void *)0); | |||
| 120 | int fd = -1; | |||
| 121 | struct stat sb; | |||
| 122 | SHA1_CTX sha1_ctx; | |||
| 123 | size_t headerlen = 0, n; | |||
| 124 | ||||
| 125 | *id = NULL((void *)0); | |||
| 126 | *blobfile = NULL((void *)0); | |||
| 127 | ||||
| 128 | SHA1Init(&sha1_ctx); | |||
| 129 | ||||
| 130 | fd = open(ondisk_path, O_RDONLY0x0000 | O_NOFOLLOW0x0100); | |||
| 131 | if (fd == -1) { | |||
| 132 | if (errno(*__errno()) != ELOOP62) | |||
| 133 | return got_error_from_errno2("open", ondisk_path); | |||
| 134 | ||||
| 135 | if (lstat(ondisk_path, &sb) == -1) { | |||
| 136 | err = got_error_from_errno2("lstat", ondisk_path); | |||
| 137 | goto done; | |||
| 138 | } | |||
| 139 | } else if (fstat(fd, &sb) == -1) { | |||
| 140 | err = got_error_from_errno2("fstat", ondisk_path); | |||
| 141 | goto done; | |||
| 142 | } | |||
| 143 | ||||
| 144 | if (asprintf(&header, "%s %lld", GOT_OBJ_LABEL_BLOB"blob", | |||
| 145 | (long long)sb.st_size) == -1) { | |||
| 146 | err = got_error_from_errno("asprintf"); | |||
| 147 | goto done; | |||
| 148 | } | |||
| 149 | headerlen = strlen(header) + 1; | |||
| 150 | SHA1Update(&sha1_ctx, header, headerlen); | |||
| 151 | ||||
| 152 | *blobfile = got_opentemp(); | |||
| 153 | if (*blobfile == NULL((void *)0)) { | |||
| 154 | err = got_error_from_errno("got_opentemp"); | |||
| 155 | goto done; | |||
| 156 | } | |||
| 157 | ||||
| 158 | n = fwrite(header, 1, headerlen, *blobfile); | |||
| 159 | if (n != headerlen) { | |||
| 160 | err = got_ferror(*blobfile, GOT_ERR_IO6); | |||
| 161 | goto done; | |||
| 162 | } | |||
| 163 | for (;;) { | |||
| 164 | char buf[PATH_MAX1024 * 8]; | |||
| 165 | ssize_t inlen; | |||
| 166 | ||||
| 167 | if (S_ISLNK(sb.st_mode)((sb.st_mode & 0170000) == 0120000)) { | |||
| 168 | inlen = readlink(ondisk_path, buf, sizeof(buf)); | |||
| 169 | if (inlen == -1) { | |||
| 170 | err = got_error_from_errno("readlink"); | |||
| 171 | goto done; | |||
| 172 | } | |||
| 173 | } else { | |||
| 174 | inlen = read(fd, buf, sizeof(buf)); | |||
| 175 | if (inlen == -1) { | |||
| 176 | err = got_error_from_errno("read"); | |||
| 177 | goto done; | |||
| 178 | } | |||
| 179 | } | |||
| 180 | if (inlen == 0) | |||
| 181 | break; /* EOF */ | |||
| 182 | SHA1Update(&sha1_ctx, buf, inlen); | |||
| 183 | n = fwrite(buf, 1, inlen, *blobfile); | |||
| 184 | if (n != inlen) { | |||
| 185 | err = got_ferror(*blobfile, GOT_ERR_IO6); | |||
| 186 | goto done; | |||
| 187 | } | |||
| 188 | if (S_ISLNK(sb.st_mode)((sb.st_mode & 0170000) == 0120000)) | |||
| 189 | break; | |||
| 190 | } | |||
| 191 | ||||
| 192 | *id = malloc(sizeof(**id)); | |||
| 193 | if (*id == NULL((void *)0)) { | |||
| 194 | err = got_error_from_errno("malloc"); | |||
| 195 | goto done; | |||
| 196 | } | |||
| 197 | SHA1Final((*id)->sha1, &sha1_ctx); | |||
| 198 | ||||
| 199 | if (fflush(*blobfile) != 0) { | |||
| 200 | err = got_error_from_errno("fflush"); | |||
| 201 | goto done; | |||
| 202 | } | |||
| 203 | rewind(*blobfile); | |||
| 204 | done: | |||
| 205 | free(header); | |||
| 206 | if (fd != -1 && close(fd) == -1 && err == NULL((void *)0)) | |||
| 207 | err = got_error_from_errno("close"); | |||
| 208 | if (err) { | |||
| 209 | free(*id); | |||
| 210 | *id = NULL((void *)0); | |||
| 211 | if (*blobfile) { | |||
| 212 | fclose(*blobfile); | |||
| 213 | *blobfile = NULL((void *)0); | |||
| 214 | } | |||
| 215 | } | |||
| 216 | return err; | |||
| 217 | } | |||
| 218 | ||||
| 219 | const struct got_error * | |||
| 220 | got_object_blob_create(struct got_object_id **id, const char *ondisk_path, | |||
| 221 | struct got_repository *repo) | |||
| 222 | { | |||
| 223 | const struct got_error *err = NULL((void *)0); | |||
| 224 | FILE *blobfile = NULL((void *)0); | |||
| 225 | ||||
| 226 | err = got_object_blob_file_create(id, &blobfile, ondisk_path); | |||
| 227 | if (err) | |||
| 228 | return err; | |||
| 229 | ||||
| 230 | err = create_object_file(*id, blobfile, repo); | |||
| 231 | if (fclose(blobfile) == EOF(-1) && err == NULL((void *)0)) | |||
| 232 | err = got_error_from_errno("fclose"); | |||
| 233 | if (err) { | |||
| 234 | free(*id); | |||
| 235 | *id = NULL((void *)0); | |||
| 236 | } | |||
| 237 | return err; | |||
| 238 | } | |||
| 239 | ||||
| 240 | static const struct got_error * | |||
| 241 | te_mode2str(char *buf, size_t len, struct got_tree_entry *te) | |||
| 242 | { | |||
| 243 | int ret; | |||
| 244 | mode_t mode; | |||
| 245 | ||||
| 246 | /* | |||
| 247 | * Some Git implementations are picky about modes seen in tree entries. | |||
| 248 | * For best compatibility we normalize the file/directory mode here. | |||
| 249 | * Note that we do not support committing symlinks. | |||
| 250 | */ | |||
| 251 | if (S_ISREG(te->mode)((te->mode & 0170000) == 0100000)) { | |||
| 252 | mode = GOT_DEFAULT_FILE_MODE(0100000 | 0000400|0000200 | 0000040 | 0000004); | |||
| 253 | if (te->mode & (S_IXUSR0000100 | S_IXGRP0000010 | S_IXOTH0000001)) | |||
| 254 | mode |= S_IXUSR0000100 | S_IXGRP0000010 | S_IXOTH0000001; | |||
| 255 | } else if (got_object_tree_entry_is_submodule(te)) | |||
| 256 | mode = S_IFDIR0040000 | S_IFLNK0120000; | |||
| 257 | else if (S_ISLNK(te->mode)((te->mode & 0170000) == 0120000)) | |||
| 258 | mode = S_IFLNK0120000; /* Git leaves all the other bits unset. */ | |||
| 259 | else if (S_ISDIR(te->mode)((te->mode & 0170000) == 0040000)) | |||
| 260 | mode = S_IFDIR0040000; /* Git leaves all the other bits unset. */ | |||
| 261 | else | |||
| 262 | return got_error(GOT_ERR_BAD_FILETYPE3); | |||
| 263 | ||||
| 264 | ret = snprintf(buf, len, "%o ", mode); | |||
| 265 | if (ret == -1 || ret >= len) | |||
| 266 | return got_error(GOT_ERR_NO_SPACE9); | |||
| 267 | return NULL((void *)0); | |||
| 268 | } | |||
| 269 | ||||
| 270 | /* | |||
| 271 | * Git expects directory tree entries to be sorted with an imaginary slash | |||
| 272 | * appended to their name, and will break otherwise. Let's be nice. | |||
| 273 | * This function is intended to be used with mergesort(3) to sort an | |||
| 274 | * array of pointers to struct got_tree_entry objects. | |||
| 275 | */ | |||
| 276 | static int | |||
| 277 | sort_tree_entries_the_way_git_likes_it(const void *arg1, const void *arg2) | |||
| 278 | { | |||
| 279 | struct got_tree_entry * const *te1 = arg1; | |||
| 280 | struct got_tree_entry * const *te2 = arg2; | |||
| 281 | char name1[NAME_MAX255 + 2]; | |||
| 282 | char name2[NAME_MAX255 + 2]; | |||
| 283 | ||||
| 284 | strlcpy(name1, (*te1)->name, sizeof(name1)); | |||
| 285 | strlcpy(name2, (*te2)->name, sizeof(name2)); | |||
| 286 | if (S_ISDIR((*te1)->mode)(((*te1)->mode & 0170000) == 0040000)) | |||
| 287 | strlcat(name1, "/", sizeof(name1)); | |||
| 288 | if (S_ISDIR((*te2)->mode)(((*te2)->mode & 0170000) == 0040000)) | |||
| 289 | strlcat(name2, "/", sizeof(name2)); | |||
| 290 | return strcmp(name1, name2); | |||
| 291 | } | |||
| 292 | ||||
| 293 | const struct got_error * | |||
| 294 | got_object_tree_create(struct got_object_id **id, | |||
| 295 | struct got_pathlist_head *paths, int nentries, struct got_repository *repo) | |||
| 296 | { | |||
| 297 | const struct got_error *err = NULL((void *)0); | |||
| 298 | char modebuf[sizeof("100644 ")]; | |||
| 299 | SHA1_CTX sha1_ctx; | |||
| 300 | char *header = NULL((void *)0); | |||
| 301 | size_t headerlen, len = 0, n; | |||
| 302 | FILE *treefile = NULL((void *)0); | |||
| 303 | struct got_pathlist_entry *pe; | |||
| 304 | struct got_tree_entry **sorted_entries; | |||
| 305 | struct got_tree_entry *te; | |||
| 306 | int i; | |||
| 307 | ||||
| 308 | *id = NULL((void *)0); | |||
| 309 | ||||
| 310 | SHA1Init(&sha1_ctx); | |||
| 311 | ||||
| 312 | sorted_entries = calloc(nentries, sizeof(struct got_tree_entry *)); | |||
| 313 | if (sorted_entries == NULL((void *)0)) | |||
| 314 | return got_error_from_errno("calloc"); | |||
| 315 | ||||
| 316 | i = 0; | |||
| 317 | TAILQ_FOREACH(pe, paths, entry)for((pe) = ((paths)->tqh_first); (pe) != ((void *)0); (pe) = ((pe)->entry.tqe_next)) | |||
| 318 | sorted_entries[i++] = pe->data; | |||
| 319 | mergesort(sorted_entries, nentries, sizeof(struct got_tree_entry *), | |||
| 320 | sort_tree_entries_the_way_git_likes_it); | |||
| 321 | ||||
| 322 | for (i = 0; i < nentries; i++) { | |||
| 323 | te = sorted_entries[i]; | |||
| 324 | err = te_mode2str(modebuf, sizeof(modebuf), te); | |||
| 325 | if (err) | |||
| 326 | goto done; | |||
| 327 | len += strlen(modebuf) + strlen(te->name) + 1 + | |||
| 328 | SHA1_DIGEST_LENGTH20; | |||
| 329 | } | |||
| 330 | ||||
| 331 | if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_TREE"tree", len) == -1) { | |||
| 332 | err = got_error_from_errno("asprintf"); | |||
| 333 | goto done; | |||
| 334 | } | |||
| 335 | headerlen = strlen(header) + 1; | |||
| 336 | SHA1Update(&sha1_ctx, header, headerlen); | |||
| 337 | ||||
| 338 | treefile = got_opentemp(); | |||
| 339 | if (treefile == NULL((void *)0)) { | |||
| 340 | err = got_error_from_errno("got_opentemp"); | |||
| 341 | goto done; | |||
| 342 | } | |||
| 343 | ||||
| 344 | n = fwrite(header, 1, headerlen, treefile); | |||
| 345 | if (n != headerlen) { | |||
| 346 | err = got_ferror(treefile, GOT_ERR_IO6); | |||
| 347 | goto done; | |||
| 348 | } | |||
| 349 | ||||
| 350 | for (i = 0; i < nentries; i++) { | |||
| 351 | te = sorted_entries[i]; | |||
| 352 | err = te_mode2str(modebuf, sizeof(modebuf), te); | |||
| 353 | if (err) | |||
| 354 | goto done; | |||
| 355 | len = strlen(modebuf); | |||
| 356 | n = fwrite(modebuf, 1, len, treefile); | |||
| 357 | if (n != len) { | |||
| 358 | err = got_ferror(treefile, GOT_ERR_IO6); | |||
| 359 | goto done; | |||
| 360 | } | |||
| 361 | SHA1Update(&sha1_ctx, modebuf, len); | |||
| 362 | ||||
| 363 | len = strlen(te->name) + 1; /* must include NUL */ | |||
| 364 | n = fwrite(te->name, 1, len, treefile); | |||
| 365 | if (n != len) { | |||
| 366 | err = got_ferror(treefile, GOT_ERR_IO6); | |||
| 367 | goto done; | |||
| 368 | } | |||
| 369 | SHA1Update(&sha1_ctx, te->name, len); | |||
| 370 | ||||
| 371 | len = SHA1_DIGEST_LENGTH20; | |||
| 372 | n = fwrite(te->id.sha1, 1, len, treefile); | |||
| 373 | if (n != len) { | |||
| 374 | err = got_ferror(treefile, GOT_ERR_IO6); | |||
| 375 | goto done; | |||
| 376 | } | |||
| 377 | SHA1Update(&sha1_ctx, te->id.sha1, len); | |||
| 378 | } | |||
| 379 | ||||
| 380 | *id = malloc(sizeof(**id)); | |||
| 381 | if (*id == NULL((void *)0)) { | |||
| 382 | err = got_error_from_errno("malloc"); | |||
| 383 | goto done; | |||
| 384 | } | |||
| 385 | SHA1Final((*id)->sha1, &sha1_ctx); | |||
| 386 | ||||
| 387 | if (fflush(treefile) != 0) { | |||
| 388 | err = got_error_from_errno("fflush"); | |||
| 389 | goto done; | |||
| 390 | } | |||
| 391 | rewind(treefile); | |||
| 392 | ||||
| 393 | err = create_object_file(*id, treefile, repo); | |||
| 394 | done: | |||
| 395 | free(header); | |||
| 396 | free(sorted_entries); | |||
| 397 | if (treefile && fclose(treefile) == EOF(-1) && err == NULL((void *)0)) | |||
| 398 | err = got_error_from_errno("fclose"); | |||
| 399 | if (err) { | |||
| 400 | free(*id); | |||
| 401 | *id = NULL((void *)0); | |||
| 402 | } | |||
| 403 | return err; | |||
| 404 | } | |||
| 405 | ||||
| 406 | const struct got_error * | |||
| 407 | got_object_commit_create(struct got_object_id **id, | |||
| 408 | struct got_object_id *tree_id, struct got_object_id_queue *parent_ids, | |||
| 409 | int nparents, const char *author, time_t author_time, | |||
| 410 | const char *committer, time_t committer_time, | |||
| 411 | const char *logmsg, struct got_repository *repo) | |||
| 412 | { | |||
| 413 | const struct got_error *err = NULL((void *)0); | |||
| 414 | SHA1_CTX sha1_ctx; | |||
| 415 | char *header = NULL((void *)0), *tree_str = NULL((void *)0); | |||
| 416 | char *author_str = NULL((void *)0), *committer_str = NULL((void *)0); | |||
| 417 | char *id_str = NULL((void *)0); | |||
| 418 | size_t headerlen, len = 0, n; | |||
| 419 | FILE *commitfile = NULL((void *)0); | |||
| 420 | struct got_object_qid *qid; | |||
| 421 | char *msg0, *msg; | |||
| 422 | ||||
| 423 | *id = NULL((void *)0); | |||
| 424 | ||||
| 425 | SHA1Init(&sha1_ctx); | |||
| 426 | ||||
| 427 | msg0 = strdup(logmsg); | |||
| ||||
| 428 | if (msg0 == NULL((void *)0)) | |||
| 429 | return got_error_from_errno("strdup"); | |||
| 430 | msg = msg0; | |||
| 431 | ||||
| 432 | while (isspace((unsigned char)msg[0])) | |||
| 433 | msg++; | |||
| 434 | len = strlen(msg); | |||
| 435 | while (len > 0 && isspace((unsigned char)msg[len - 1])) { | |||
| 436 | msg[len - 1] = '\0'; | |||
| 437 | len--; | |||
| 438 | } | |||
| 439 | ||||
| 440 | if (asprintf(&author_str, "%s%s %lld +0000\n", | |||
| 441 | GOT_COMMIT_LABEL_AUTHOR"author ", author, (long long)author_time) == -1) | |||
| 442 | return got_error_from_errno("asprintf"); | |||
| ||||
| 443 | ||||
| 444 | if (asprintf(&committer_str, "%s%s %lld +0000\n", | |||
| 445 | GOT_COMMIT_LABEL_COMMITTER"committer ", committer ? committer : author, | |||
| 446 | (long long)(committer ? committer_time : author_time)) | |||
| 447 | == -1) { | |||
| 448 | err = got_error_from_errno("asprintf"); | |||
| 449 | goto done; | |||
| 450 | } | |||
| 451 | ||||
| 452 | len = strlen(GOT_COMMIT_LABEL_TREE"tree ") + SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1) + | |||
| 453 | nparents * | |||
| 454 | (strlen(GOT_COMMIT_LABEL_PARENT"parent ") + SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)) + | |||
| 455 | + strlen(author_str) + strlen(committer_str) + 2 + strlen(msg); | |||
| 456 | ||||
| 457 | if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_COMMIT"commit", len) == -1) { | |||
| 458 | err = got_error_from_errno("asprintf"); | |||
| 459 | goto done; | |||
| 460 | } | |||
| 461 | headerlen = strlen(header) + 1; | |||
| 462 | SHA1Update(&sha1_ctx, header, headerlen); | |||
| 463 | ||||
| 464 | commitfile = got_opentemp(); | |||
| 465 | if (commitfile == NULL((void *)0)) { | |||
| 466 | err = got_error_from_errno("got_opentemp"); | |||
| 467 | goto done; | |||
| 468 | } | |||
| 469 | ||||
| 470 | n = fwrite(header, 1, headerlen, commitfile); | |||
| 471 | if (n != headerlen) { | |||
| 472 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 473 | goto done; | |||
| 474 | } | |||
| 475 | ||||
| 476 | err = got_object_id_str(&id_str, tree_id); | |||
| 477 | if (err) | |||
| 478 | goto done; | |||
| 479 | if (asprintf(&tree_str, "%s%s\n", GOT_COMMIT_LABEL_TREE"tree ", id_str) | |||
| 480 | == -1) { | |||
| 481 | err = got_error_from_errno("asprintf"); | |||
| 482 | goto done; | |||
| 483 | } | |||
| 484 | len = strlen(tree_str); | |||
| 485 | SHA1Update(&sha1_ctx, tree_str, len); | |||
| 486 | n = fwrite(tree_str, 1, len, commitfile); | |||
| 487 | if (n != len) { | |||
| 488 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 489 | goto done; | |||
| 490 | } | |||
| 491 | ||||
| 492 | if (parent_ids) { | |||
| 493 | SIMPLEQ_FOREACH(qid, parent_ids, entry)for((qid) = ((parent_ids)->sqh_first); (qid) != ((void *)0 ); (qid) = ((qid)->entry.sqe_next)) { | |||
| 494 | char *parent_str = NULL((void *)0); | |||
| 495 | ||||
| 496 | free(id_str); | |||
| 497 | ||||
| 498 | err = got_object_id_str(&id_str, qid->id); | |||
| 499 | if (err) | |||
| 500 | goto done; | |||
| 501 | if (asprintf(&parent_str, "%s%s\n", | |||
| 502 | GOT_COMMIT_LABEL_PARENT"parent ", id_str) == -1) { | |||
| 503 | err = got_error_from_errno("asprintf"); | |||
| 504 | goto done; | |||
| 505 | } | |||
| 506 | len = strlen(parent_str); | |||
| 507 | SHA1Update(&sha1_ctx, parent_str, len); | |||
| 508 | n = fwrite(parent_str, 1, len, commitfile); | |||
| 509 | if (n != len) { | |||
| 510 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 511 | free(parent_str); | |||
| 512 | goto done; | |||
| 513 | } | |||
| 514 | free(parent_str); | |||
| 515 | } | |||
| 516 | } | |||
| 517 | ||||
| 518 | len = strlen(author_str); | |||
| 519 | SHA1Update(&sha1_ctx, author_str, len); | |||
| 520 | n = fwrite(author_str, 1, len, commitfile); | |||
| 521 | if (n != len) { | |||
| 522 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 523 | goto done; | |||
| 524 | } | |||
| 525 | ||||
| 526 | len = strlen(committer_str); | |||
| 527 | SHA1Update(&sha1_ctx, committer_str, len); | |||
| 528 | n = fwrite(committer_str, 1, len, commitfile); | |||
| 529 | if (n != len) { | |||
| 530 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 531 | goto done; | |||
| 532 | } | |||
| 533 | ||||
| 534 | SHA1Update(&sha1_ctx, "\n", 1); | |||
| 535 | n = fwrite("\n", 1, 1, commitfile); | |||
| 536 | if (n != 1) { | |||
| 537 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 538 | goto done; | |||
| 539 | } | |||
| 540 | ||||
| 541 | len = strlen(msg); | |||
| 542 | SHA1Update(&sha1_ctx, msg, len); | |||
| 543 | n = fwrite(msg, 1, len, commitfile); | |||
| 544 | if (n != len) { | |||
| 545 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 546 | goto done; | |||
| 547 | } | |||
| 548 | ||||
| 549 | SHA1Update(&sha1_ctx, "\n", 1); | |||
| 550 | n = fwrite("\n", 1, 1, commitfile); | |||
| 551 | if (n != 1) { | |||
| 552 | err = got_ferror(commitfile, GOT_ERR_IO6); | |||
| 553 | goto done; | |||
| 554 | } | |||
| 555 | ||||
| 556 | *id = malloc(sizeof(**id)); | |||
| 557 | if (*id == NULL((void *)0)) { | |||
| 558 | err = got_error_from_errno("malloc"); | |||
| 559 | goto done; | |||
| 560 | } | |||
| 561 | SHA1Final((*id)->sha1, &sha1_ctx); | |||
| 562 | ||||
| 563 | if (fflush(commitfile) != 0) { | |||
| 564 | err = got_error_from_errno("fflush"); | |||
| 565 | goto done; | |||
| 566 | } | |||
| 567 | rewind(commitfile); | |||
| 568 | ||||
| 569 | err = create_object_file(*id, commitfile, repo); | |||
| 570 | done: | |||
| 571 | free(msg0); | |||
| 572 | free(header); | |||
| 573 | free(tree_str); | |||
| 574 | free(author_str); | |||
| 575 | free(committer_str); | |||
| 576 | if (commitfile && fclose(commitfile) == EOF(-1) && err == NULL((void *)0)) | |||
| 577 | err = got_error_from_errno("fclose"); | |||
| 578 | if (err) { | |||
| 579 | free(*id); | |||
| 580 | *id = NULL((void *)0); | |||
| 581 | } | |||
| 582 | return err; | |||
| 583 | } | |||
| 584 | ||||
| 585 | const struct got_error * | |||
| 586 | got_object_tag_create(struct got_object_id **id, | |||
| 587 | const char *tag_name, struct got_object_id *object_id, const char *tagger, | |||
| 588 | time_t tagger_time, const char *tagmsg, struct got_repository *repo) | |||
| 589 | { | |||
| 590 | const struct got_error *err = NULL((void *)0); | |||
| 591 | SHA1_CTX sha1_ctx; | |||
| 592 | char *header = NULL((void *)0); | |||
| 593 | char *tag_str = NULL((void *)0), *tagger_str = NULL((void *)0); | |||
| 594 | char *id_str = NULL((void *)0), *obj_str = NULL((void *)0), *type_str = NULL((void *)0); | |||
| 595 | size_t headerlen, len = 0, n; | |||
| 596 | FILE *tagfile = NULL((void *)0); | |||
| 597 | char *msg0 = NULL((void *)0), *msg; | |||
| 598 | const char *obj_type_str; | |||
| 599 | int obj_type; | |||
| 600 | ||||
| 601 | *id = NULL((void *)0); | |||
| 602 | ||||
| 603 | SHA1Init(&sha1_ctx); | |||
| 604 | ||||
| 605 | err = got_object_id_str(&id_str, object_id); | |||
| 606 | if (err) | |||
| 607 | goto done; | |||
| 608 | if (asprintf(&obj_str, "%s%s\n", GOT_TAG_LABEL_OBJECT"object ", id_str) == -1) { | |||
| 609 | err = got_error_from_errno("asprintf"); | |||
| 610 | goto done; | |||
| 611 | } | |||
| 612 | ||||
| 613 | err = got_object_get_type(&obj_type, repo, object_id); | |||
| 614 | if (err) | |||
| 615 | goto done; | |||
| 616 | ||||
| 617 | switch (obj_type) { | |||
| 618 | case GOT_OBJ_TYPE_BLOB3: | |||
| 619 | obj_type_str = GOT_OBJ_LABEL_BLOB"blob"; | |||
| 620 | break; | |||
| 621 | case GOT_OBJ_TYPE_TREE2: | |||
| 622 | obj_type_str = GOT_OBJ_LABEL_TREE"tree"; | |||
| 623 | break; | |||
| 624 | case GOT_OBJ_TYPE_COMMIT1: | |||
| 625 | obj_type_str = GOT_OBJ_LABEL_COMMIT"commit"; | |||
| 626 | break; | |||
| 627 | case GOT_OBJ_TYPE_TAG4: | |||
| 628 | obj_type_str = GOT_OBJ_LABEL_TAG"tag"; | |||
| 629 | break; | |||
| 630 | default: | |||
| 631 | err = got_error(GOT_ERR_OBJ_TYPE11); | |||
| 632 | goto done; | |||
| 633 | } | |||
| 634 | ||||
| 635 | if (asprintf(&type_str, "%s%s\n", GOT_TAG_LABEL_TYPE"type ", | |||
| 636 | obj_type_str) == -1) { | |||
| 637 | err = got_error_from_errno("asprintf"); | |||
| 638 | goto done; | |||
| 639 | } | |||
| 640 | ||||
| 641 | if (asprintf(&tag_str, "%s%s\n", GOT_TAG_LABEL_TAG"tag ", tag_name) == -1) { | |||
| 642 | err = got_error_from_errno("asprintf"); | |||
| 643 | goto done; | |||
| 644 | } | |||
| 645 | ||||
| 646 | if (asprintf(&tagger_str, "%s%s %lld +0000\n", | |||
| 647 | GOT_TAG_LABEL_TAGGER"tagger ", tagger, (long long)tagger_time) == -1) | |||
| 648 | return got_error_from_errno("asprintf"); | |||
| 649 | ||||
| 650 | msg0 = strdup(tagmsg); | |||
| 651 | if (msg0 == NULL((void *)0)) { | |||
| 652 | err = got_error_from_errno("strdup"); | |||
| 653 | goto done; | |||
| 654 | } | |||
| 655 | msg = msg0; | |||
| 656 | ||||
| 657 | while (isspace((unsigned char)msg[0])) | |||
| 658 | msg++; | |||
| 659 | ||||
| 660 | len = strlen(obj_str) + strlen(type_str) + strlen(tag_str) + | |||
| 661 | strlen(tagger_str) + 1 + strlen(msg) + 1; | |||
| 662 | ||||
| 663 | if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_TAG"tag", len) == -1) { | |||
| 664 | err = got_error_from_errno("asprintf"); | |||
| 665 | goto done; | |||
| 666 | } | |||
| 667 | ||||
| 668 | headerlen = strlen(header) + 1; | |||
| 669 | SHA1Update(&sha1_ctx, header, headerlen); | |||
| 670 | ||||
| 671 | tagfile = got_opentemp(); | |||
| 672 | if (tagfile == NULL((void *)0)) { | |||
| 673 | err = got_error_from_errno("got_opentemp"); | |||
| 674 | goto done; | |||
| 675 | } | |||
| 676 | ||||
| 677 | n = fwrite(header, 1, headerlen, tagfile); | |||
| 678 | if (n != headerlen) { | |||
| 679 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 680 | goto done; | |||
| 681 | } | |||
| 682 | len = strlen(obj_str); | |||
| 683 | SHA1Update(&sha1_ctx, obj_str, len); | |||
| 684 | n = fwrite(obj_str, 1, len, tagfile); | |||
| 685 | if (n != len) { | |||
| 686 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 687 | goto done; | |||
| 688 | } | |||
| 689 | len = strlen(type_str); | |||
| 690 | SHA1Update(&sha1_ctx, type_str, len); | |||
| 691 | n = fwrite(type_str, 1, len, tagfile); | |||
| 692 | if (n != len) { | |||
| 693 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 694 | goto done; | |||
| 695 | } | |||
| 696 | ||||
| 697 | len = strlen(tag_str); | |||
| 698 | SHA1Update(&sha1_ctx, tag_str, len); | |||
| 699 | n = fwrite(tag_str, 1, len, tagfile); | |||
| 700 | if (n != len) { | |||
| 701 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 702 | goto done; | |||
| 703 | } | |||
| 704 | ||||
| 705 | len = strlen(tagger_str); | |||
| 706 | SHA1Update(&sha1_ctx, tagger_str, len); | |||
| 707 | n = fwrite(tagger_str, 1, len, tagfile); | |||
| 708 | if (n != len) { | |||
| 709 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 710 | goto done; | |||
| 711 | } | |||
| 712 | ||||
| 713 | SHA1Update(&sha1_ctx, "\n", 1); | |||
| 714 | n = fwrite("\n", 1, 1, tagfile); | |||
| 715 | if (n != 1) { | |||
| 716 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 717 | goto done; | |||
| 718 | } | |||
| 719 | ||||
| 720 | len = strlen(msg); | |||
| 721 | SHA1Update(&sha1_ctx, msg, len); | |||
| 722 | n = fwrite(msg, 1, len, tagfile); | |||
| 723 | if (n != len) { | |||
| 724 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 725 | goto done; | |||
| 726 | } | |||
| 727 | ||||
| 728 | SHA1Update(&sha1_ctx, "\n", 1); | |||
| 729 | n = fwrite("\n", 1, 1, tagfile); | |||
| 730 | if (n != 1) { | |||
| 731 | err = got_ferror(tagfile, GOT_ERR_IO6); | |||
| 732 | goto done; | |||
| 733 | } | |||
| 734 | ||||
| 735 | *id = malloc(sizeof(**id)); | |||
| 736 | if (*id == NULL((void *)0)) { | |||
| 737 | err = got_error_from_errno("malloc"); | |||
| 738 | goto done; | |||
| 739 | } | |||
| 740 | SHA1Final((*id)->sha1, &sha1_ctx); | |||
| 741 | ||||
| 742 | if (fflush(tagfile) != 0) { | |||
| 743 | err = got_error_from_errno("fflush"); | |||
| 744 | goto done; | |||
| 745 | } | |||
| 746 | rewind(tagfile); | |||
| 747 | ||||
| 748 | err = create_object_file(*id, tagfile, repo); | |||
| 749 | done: | |||
| 750 | free(msg0); | |||
| 751 | free(header); | |||
| 752 | free(obj_str); | |||
| 753 | free(tagger_str); | |||
| 754 | if (tagfile && fclose(tagfile) == EOF(-1) && err == NULL((void *)0)) | |||
| 755 | err = got_error_from_errno("fclose"); | |||
| 756 | if (err) { | |||
| 757 | free(*id); | |||
| 758 | *id = NULL((void *)0); | |||
| 759 | } | |||
| 760 | return err; | |||
| 761 | } |