attempt to make cmdline tests involing http-server more reliable
[got-portable.git] / lib / worktree.c
blob8c54bfac896cabfb504fc22d3c29d924c6364f6b
1 /*
2 * Copyright (c) 2018, 2019, 2020 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/stat.h>
20 #include <sys/queue.h>
22 #include <dirent.h>
23 #include <limits.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <time.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <zlib.h>
33 #include <fnmatch.h>
34 #include <libgen.h>
36 #include "got_error.h"
37 #include "got_repository.h"
38 #include "got_reference.h"
39 #include "got_object.h"
40 #include "got_path.h"
41 #include "got_cancel.h"
42 #include "got_worktree.h"
43 #include "got_opentemp.h"
44 #include "got_diff.h"
46 #include "got_lib_worktree.h"
47 #include "got_lib_hash.h"
48 #include "got_lib_fileindex.h"
49 #include "got_lib_inflate.h"
50 #include "got_lib_delta.h"
51 #include "got_lib_object.h"
52 #include "got_lib_object_parse.h"
53 #include "got_lib_object_create.h"
54 #include "got_lib_object_idset.h"
55 #include "got_lib_diff.h"
56 #include "got_lib_gotconfig.h"
58 #ifndef MIN
59 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
60 #endif
62 #define GOT_MERGE_LABEL_MERGED "merged change"
63 #define GOT_MERGE_LABEL_BASE "3-way merge base"
65 static mode_t
66 apply_umask(mode_t mode)
68 mode_t um;
70 um = umask(000);
71 umask(um);
72 return mode & ~um;
75 static const struct got_error *
76 create_meta_file(const char *path_got, const char *name, const char *content)
78 const struct got_error *err = NULL;
79 char *path;
81 if (asprintf(&path, "%s/%s", path_got, name) == -1)
82 return got_error_from_errno("asprintf");
84 err = got_path_create_file(path, content);
85 free(path);
86 return err;
89 static const struct got_error *
90 update_meta_file(const char *path_got, const char *name, const char *content)
92 const struct got_error *err = NULL;
93 FILE *tmpfile = NULL;
94 char *tmppath = NULL;
95 char *path = NULL;
97 if (asprintf(&path, "%s/%s", path_got, name) == -1) {
98 err = got_error_from_errno("asprintf");
99 path = NULL;
100 goto done;
103 err = got_opentemp_named(&tmppath, &tmpfile, path, "");
104 if (err)
105 goto done;
107 if (content) {
108 int len = fprintf(tmpfile, "%s\n", content);
109 if (len != strlen(content) + 1) {
110 err = got_error_from_errno2("fprintf", tmppath);
111 goto done;
115 if (rename(tmppath, path) != 0) {
116 err = got_error_from_errno3("rename", tmppath, path);
117 unlink(tmppath);
118 goto done;
121 done:
122 if (fclose(tmpfile) == EOF && err == NULL)
123 err = got_error_from_errno2("fclose", tmppath);
124 free(tmppath);
125 return err;
128 static const struct got_error *
129 write_head_ref(const char *path_got, struct got_reference *head_ref)
131 const struct got_error *err = NULL;
132 char *refstr = NULL;
134 if (got_ref_is_symbolic(head_ref)) {
135 refstr = got_ref_to_str(head_ref);
136 if (refstr == NULL)
137 return got_error_from_errno("got_ref_to_str");
138 } else {
139 refstr = strdup(got_ref_get_name(head_ref));
140 if (refstr == NULL)
141 return got_error_from_errno("strdup");
143 err = update_meta_file(path_got, GOT_WORKTREE_HEAD_REF, refstr);
144 free(refstr);
145 return err;
148 const struct got_error *
149 got_worktree_init(const char *path, struct got_reference *head_ref,
150 const char *prefix, const char *meta_dir, struct got_repository *repo)
152 const struct got_error *err = NULL;
153 struct got_object_id *commit_id = NULL;
154 uuid_t uuid;
155 uint32_t uuid_status;
156 int obj_type;
157 char *path_got = NULL;
158 char *formatstr = NULL;
159 char *absprefix = NULL;
160 char *basestr = NULL;
161 char *uuidstr = NULL;
163 if (strcmp(path, got_repo_get_path(repo)) == 0) {
164 err = got_error(GOT_ERR_WORKTREE_REPO);
165 goto done;
168 err = got_ref_resolve(&commit_id, repo, head_ref);
169 if (err)
170 return err;
171 err = got_object_get_type(&obj_type, repo, commit_id);
172 if (err)
173 return err;
174 if (obj_type != GOT_OBJ_TYPE_COMMIT)
175 return got_error(GOT_ERR_OBJ_TYPE);
177 if (!got_path_is_absolute(prefix)) {
178 if (asprintf(&absprefix, "/%s", prefix) == -1)
179 return got_error_from_errno("asprintf");
182 /* Create top-level directory (may already exist). */
183 if (mkdir(path, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
184 err = got_error_from_errno2("mkdir", path);
185 goto done;
188 /* Create .got/.cvg directory (may already exist). */
189 if (asprintf(&path_got, "%s/%s", path, meta_dir) == -1) {
190 err = got_error_from_errno("asprintf");
191 goto done;
193 if (mkdir(path_got, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
194 err = got_error_from_errno2("mkdir", path_got);
195 goto done;
198 /* Create an empty lock file. */
199 err = create_meta_file(path_got, GOT_WORKTREE_LOCK, NULL);
200 if (err)
201 goto done;
203 /* Create an empty file index. */
204 err = create_meta_file(path_got, GOT_WORKTREE_FILE_INDEX, NULL);
205 if (err)
206 goto done;
208 /* Write the HEAD reference. */
209 err = write_head_ref(path_got, head_ref);
210 if (err)
211 goto done;
213 /* Record our base commit. */
214 err = got_object_id_str(&basestr, commit_id);
215 if (err)
216 goto done;
217 err = create_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, basestr);
218 if (err)
219 goto done;
221 /* Store path to repository. */
222 err = create_meta_file(path_got, GOT_WORKTREE_REPOSITORY,
223 got_repo_get_path(repo));
224 if (err)
225 goto done;
227 /* Store in-repository path prefix. */
228 err = create_meta_file(path_got, GOT_WORKTREE_PATH_PREFIX,
229 absprefix ? absprefix : prefix);
230 if (err)
231 goto done;
233 /* Generate UUID. */
234 uuid_create(&uuid, &uuid_status);
235 if (uuid_status != uuid_s_ok) {
236 err = got_error_uuid(uuid_status, "uuid_create");
237 goto done;
239 uuid_to_string(&uuid, &uuidstr, &uuid_status);
240 if (uuid_status != uuid_s_ok) {
241 err = got_error_uuid(uuid_status, "uuid_to_string");
242 goto done;
244 err = create_meta_file(path_got, GOT_WORKTREE_UUID, uuidstr);
245 if (err)
246 goto done;
248 /* Stamp work tree with format file. */
249 if (asprintf(&formatstr, "%d", GOT_WORKTREE_FORMAT_VERSION) == -1) {
250 err = got_error_from_errno("asprintf");
251 goto done;
253 err = create_meta_file(path_got, GOT_WORKTREE_FORMAT, formatstr);
254 if (err)
255 goto done;
257 done:
258 free(commit_id);
259 free(path_got);
260 free(formatstr);
261 free(absprefix);
262 free(basestr);
263 free(uuidstr);
264 return err;
267 const struct got_error *
268 got_worktree_match_path_prefix(int *match, struct got_worktree *worktree,
269 const char *path_prefix)
271 char *absprefix = NULL;
273 if (!got_path_is_absolute(path_prefix)) {
274 if (asprintf(&absprefix, "/%s", path_prefix) == -1)
275 return got_error_from_errno("asprintf");
277 *match = (strcmp(absprefix ? absprefix : path_prefix,
278 worktree->path_prefix) == 0);
279 free(absprefix);
280 return NULL;
283 const char *
284 got_worktree_get_head_ref_name(struct got_worktree *worktree)
286 return worktree->head_ref_name;
289 const struct got_error *
290 got_worktree_set_head_ref(struct got_worktree *worktree,
291 struct got_reference *head_ref)
293 const struct got_error *err = NULL;
294 char *path_got = NULL, *head_ref_name = NULL;
296 if (asprintf(&path_got, "%s/%s", worktree->root_path,
297 worktree->meta_dir) == -1) {
298 err = got_error_from_errno("asprintf");
299 path_got = NULL;
300 goto done;
303 head_ref_name = strdup(got_ref_get_name(head_ref));
304 if (head_ref_name == NULL) {
305 err = got_error_from_errno("strdup");
306 goto done;
309 err = write_head_ref(path_got, head_ref);
310 if (err)
311 goto done;
313 free(worktree->head_ref_name);
314 worktree->head_ref_name = head_ref_name;
315 done:
316 free(path_got);
317 if (err)
318 free(head_ref_name);
319 return err;
322 struct got_object_id *
323 got_worktree_get_base_commit_id(struct got_worktree *worktree)
325 return worktree->base_commit_id;
328 const struct got_error *
329 got_worktree_set_base_commit_id(struct got_worktree *worktree,
330 struct got_repository *repo, struct got_object_id *commit_id)
332 const struct got_error *err;
333 struct got_object *obj = NULL;
334 char *id_str = NULL;
335 char *path_got = NULL;
337 if (asprintf(&path_got, "%s/%s", worktree->root_path,
338 worktree->meta_dir) == -1) {
339 err = got_error_from_errno("asprintf");
340 path_got = NULL;
341 goto done;
344 err = got_object_open(&obj, repo, commit_id);
345 if (err)
346 return err;
348 if (obj->type != GOT_OBJ_TYPE_COMMIT) {
349 err = got_error(GOT_ERR_OBJ_TYPE);
350 goto done;
353 /* Record our base commit. */
354 err = got_object_id_str(&id_str, commit_id);
355 if (err)
356 goto done;
357 err = update_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, id_str);
358 if (err)
359 goto done;
361 free(worktree->base_commit_id);
362 worktree->base_commit_id = got_object_id_dup(commit_id);
363 if (worktree->base_commit_id == NULL) {
364 err = got_error_from_errno("got_object_id_dup");
365 goto done;
367 done:
368 if (obj)
369 got_object_close(obj);
370 free(id_str);
371 free(path_got);
372 return err;
375 const struct got_gotconfig *
376 got_worktree_get_gotconfig(struct got_worktree *worktree)
378 return worktree->gotconfig;
381 static const struct got_error *
382 lock_worktree(struct got_worktree *worktree, int operation)
384 if (flock(worktree->lockfd, operation | LOCK_NB) == -1)
385 return (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY)
386 : got_error_from_errno2("flock",
387 got_worktree_get_root_path(worktree)));
388 return NULL;
391 static const struct got_error *
392 add_dir_on_disk(struct got_worktree *worktree, const char *path)
394 const struct got_error *err = NULL;
395 char *abspath;
397 /* We only accept worktree-relative paths here. */
398 if (got_path_is_absolute(path)) {
399 return got_error_fmt(GOT_ERR_BAD_PATH,
400 "%s does not accept absolute paths: %s",
401 __func__, path);
404 if (asprintf(&abspath, "%s/%s", worktree->root_path, path) == -1)
405 return got_error_from_errno("asprintf");
407 err = got_path_mkdir(abspath);
408 if (err && err->code == GOT_ERR_ERRNO && errno == EEXIST) {
409 struct stat sb;
410 err = NULL;
411 if (lstat(abspath, &sb) == -1) {
412 err = got_error_from_errno2("lstat", abspath);
413 } else if (!S_ISDIR(sb.st_mode)) {
414 /* TODO directory is obstructed; do something */
415 err = got_error_path(abspath, GOT_ERR_FILE_OBSTRUCTED);
418 free(abspath);
419 return err;
422 static const struct got_error *
423 check_file_contents_equal(int *same, FILE *f1, FILE *f2)
425 const struct got_error *err = NULL;
426 uint8_t fbuf1[8192];
427 uint8_t fbuf2[8192];
428 size_t flen1 = 0, flen2 = 0;
430 *same = 1;
432 for (;;) {
433 flen1 = fread(fbuf1, 1, sizeof(fbuf1), f1);
434 if (flen1 == 0 && ferror(f1)) {
435 err = got_error_from_errno("fread");
436 break;
438 flen2 = fread(fbuf2, 1, sizeof(fbuf2), f2);
439 if (flen2 == 0 && ferror(f2)) {
440 err = got_error_from_errno("fread");
441 break;
443 if (flen1 == 0) {
444 if (flen2 != 0)
445 *same = 0;
446 break;
447 } else if (flen2 == 0) {
448 if (flen1 != 0)
449 *same = 0;
450 break;
451 } else if (flen1 == flen2) {
452 if (memcmp(fbuf1, fbuf2, flen2) != 0) {
453 *same = 0;
454 break;
456 } else {
457 *same = 0;
458 break;
462 return err;
465 static const struct got_error *
466 check_files_equal(int *same, FILE *f1, FILE *f2)
468 struct stat sb;
469 size_t size1, size2;
471 *same = 1;
473 if (fstat(fileno(f1), &sb) != 0)
474 return got_error_from_errno("fstat");
475 size1 = sb.st_size;
477 if (fstat(fileno(f2), &sb) != 0)
478 return got_error_from_errno("fstat");
479 size2 = sb.st_size;
481 if (size1 != size2) {
482 *same = 0;
483 return NULL;
486 if (fseek(f1, 0L, SEEK_SET) == -1)
487 return got_ferror(f1, GOT_ERR_IO);
488 if (fseek(f2, 0L, SEEK_SET) == -1)
489 return got_ferror(f2, GOT_ERR_IO);
491 return check_file_contents_equal(same, f1, f2);
494 static const struct got_error *
495 copy_file_to_fd(off_t *outsize, FILE *f, int outfd)
497 uint8_t fbuf[65536];
498 size_t flen;
499 ssize_t outlen;
501 *outsize = 0;
503 if (fseek(f, 0L, SEEK_SET) == -1)
504 return got_ferror(f, GOT_ERR_IO);
506 for (;;) {
507 flen = fread(fbuf, 1, sizeof(fbuf), f);
508 if (flen == 0) {
509 if (ferror(f))
510 return got_error_from_errno("fread");
511 if (feof(f))
512 break;
514 outlen = write(outfd, fbuf, flen);
515 if (outlen == -1)
516 return got_error_from_errno("write");
517 if (outlen != flen)
518 return got_error(GOT_ERR_IO);
519 *outsize += outlen;
522 return NULL;
525 static const struct got_error *
526 merge_binary_file(int *overlapcnt, int merged_fd,
527 FILE *f_deriv, FILE *f_orig, FILE *f_deriv2,
528 const char *label_deriv, const char *label_orig, const char *label_deriv2,
529 const char *ondisk_path)
531 const struct got_error *err = NULL;
532 int same_content, changed_deriv, changed_deriv2;
533 int fd_orig = -1, fd_deriv = -1, fd_deriv2 = -1;
534 off_t size_orig = 0, size_deriv = 0, size_deriv2 = 0;
535 char *path_orig = NULL, *path_deriv = NULL, *path_deriv2 = NULL;
536 char *base_path_orig = NULL, *base_path_deriv = NULL;
537 char *base_path_deriv2 = NULL;
539 *overlapcnt = 0;
541 err = check_files_equal(&same_content, f_deriv, f_deriv2);
542 if (err)
543 return err;
545 if (same_content)
546 return copy_file_to_fd(&size_deriv, f_deriv, merged_fd);
548 err = check_files_equal(&same_content, f_deriv, f_orig);
549 if (err)
550 return err;
551 changed_deriv = !same_content;
552 err = check_files_equal(&same_content, f_deriv2, f_orig);
553 if (err)
554 return err;
555 changed_deriv2 = !same_content;
557 if (changed_deriv && changed_deriv2) {
558 *overlapcnt = 1;
559 if (asprintf(&base_path_orig, "%s-orig", ondisk_path) == -1) {
560 err = got_error_from_errno("asprintf");
561 goto done;
563 if (asprintf(&base_path_deriv, "%s-1", ondisk_path) == -1) {
564 err = got_error_from_errno("asprintf");
565 goto done;
567 if (asprintf(&base_path_deriv2, "%s-2", ondisk_path) == -1) {
568 err = got_error_from_errno("asprintf");
569 goto done;
571 err = got_opentemp_named_fd(&path_orig, &fd_orig,
572 base_path_orig, "");
573 if (err)
574 goto done;
575 err = got_opentemp_named_fd(&path_deriv, &fd_deriv,
576 base_path_deriv, "");
577 if (err)
578 goto done;
579 err = got_opentemp_named_fd(&path_deriv2, &fd_deriv2,
580 base_path_deriv2, "");
581 if (err)
582 goto done;
583 err = copy_file_to_fd(&size_orig, f_orig, fd_orig);
584 if (err)
585 goto done;
586 err = copy_file_to_fd(&size_deriv, f_deriv, fd_deriv);
587 if (err)
588 goto done;
589 err = copy_file_to_fd(&size_deriv2, f_deriv2, fd_deriv2);
590 if (err)
591 goto done;
592 if (dprintf(merged_fd, "Binary files differ and cannot be "
593 "merged automatically:\n") < 0) {
594 err = got_error_from_errno("dprintf");
595 goto done;
597 if (dprintf(merged_fd, "%s%s%s\nfile %s\n",
598 GOT_DIFF_CONFLICT_MARKER_BEGIN,
599 label_deriv ? " " : "",
600 label_deriv ? label_deriv : "",
601 path_deriv) < 0) {
602 err = got_error_from_errno("dprintf");
603 goto done;
605 if (size_orig > 0) {
606 if (dprintf(merged_fd, "%s%s%s\nfile %s\n",
607 GOT_DIFF_CONFLICT_MARKER_ORIG,
608 label_orig ? " " : "",
609 label_orig ? label_orig : "",
610 path_orig) < 0) {
611 err = got_error_from_errno("dprintf");
612 goto done;
615 if (dprintf(merged_fd, "%s\nfile %s\n%s%s%s\n",
616 GOT_DIFF_CONFLICT_MARKER_SEP,
617 path_deriv2,
618 GOT_DIFF_CONFLICT_MARKER_END,
619 label_deriv2 ? " " : "",
620 label_deriv2 ? label_deriv2 : "") < 0) {
621 err = got_error_from_errno("dprintf");
622 goto done;
624 } else if (changed_deriv)
625 err = copy_file_to_fd(&size_deriv, f_deriv, merged_fd);
626 else if (changed_deriv2)
627 err = copy_file_to_fd(&size_deriv2, f_deriv2, merged_fd);
628 done:
629 if (size_orig == 0 && path_orig && unlink(path_orig) == -1 &&
630 err == NULL)
631 err = got_error_from_errno2("unlink", path_orig);
632 if (fd_orig != -1 && close(fd_orig) == -1 && err == NULL)
633 err = got_error_from_errno2("close", path_orig);
634 if (fd_deriv != -1 && close(fd_deriv) == -1 && err == NULL)
635 err = got_error_from_errno2("close", path_deriv);
636 if (fd_deriv2 != -1 && close(fd_deriv2) == -1 && err == NULL)
637 err = got_error_from_errno2("close", path_deriv2);
638 free(path_orig);
639 free(path_deriv);
640 free(path_deriv2);
641 free(base_path_orig);
642 free(base_path_deriv);
643 free(base_path_deriv2);
644 return err;
648 * Perform a 3-way merge where the file f_orig acts as the common
649 * ancestor, the file f_deriv acts as the first derived version,
650 * and the file f_deriv2 acts as the second derived version.
651 * The merge result will be written to a new file at ondisk_path; any
652 * existing file at this path will be replaced.
654 static const struct got_error *
655 merge_file(int *local_changes_subsumed, struct got_worktree *worktree,
656 FILE *f_orig, FILE *f_deriv, FILE *f_deriv2, const char *ondisk_path,
657 const char *path, uint16_t st_mode,
658 const char *label_orig, const char *label_deriv, const char *label_deriv2,
659 enum got_diff_algorithm diff_algo, struct got_repository *repo,
660 got_worktree_checkout_cb progress_cb, void *progress_arg)
662 const struct got_error *err = NULL;
663 int merged_fd = -1;
664 FILE *f_merged = NULL;
665 char *merged_path = NULL, *base_path = NULL;
666 int overlapcnt = 0;
667 char *parent = NULL;
669 *local_changes_subsumed = 0;
671 err = got_path_dirname(&parent, ondisk_path);
672 if (err)
673 return err;
675 if (asprintf(&base_path, "%s/got-merged", parent) == -1) {
676 err = got_error_from_errno("asprintf");
677 goto done;
680 err = got_opentemp_named_fd(&merged_path, &merged_fd, base_path, "");
681 if (err)
682 goto done;
684 err = got_merge_diff3(&overlapcnt, merged_fd, f_deriv, f_orig,
685 f_deriv2, label_deriv, label_orig, label_deriv2, diff_algo);
686 if (err) {
687 if (err->code != GOT_ERR_FILE_BINARY)
688 goto done;
689 err = merge_binary_file(&overlapcnt, merged_fd, f_deriv,
690 f_orig, f_deriv2, label_deriv, label_orig, label_deriv2,
691 ondisk_path);
692 if (err)
693 goto done;
696 err = (*progress_cb)(progress_arg,
697 overlapcnt > 0 ? GOT_STATUS_CONFLICT : GOT_STATUS_MERGE, path);
698 if (err)
699 goto done;
701 if (fsync(merged_fd) != 0) {
702 err = got_error_from_errno("fsync");
703 goto done;
706 f_merged = fdopen(merged_fd, "r");
707 if (f_merged == NULL) {
708 err = got_error_from_errno("fdopen");
709 goto done;
711 merged_fd = -1;
713 /* Check if a clean merge has subsumed all local changes. */
714 if (overlapcnt == 0) {
715 err = check_files_equal(local_changes_subsumed, f_deriv,
716 f_merged);
717 if (err)
718 goto done;
721 if (fchmod(fileno(f_merged), apply_umask(st_mode)) != 0) {
722 err = got_error_from_errno2("fchmod", merged_path);
723 goto done;
726 if (rename(merged_path, ondisk_path) != 0) {
727 err = got_error_from_errno3("rename", merged_path,
728 ondisk_path);
729 goto done;
731 done:
732 if (err) {
733 if (merged_path)
734 unlink(merged_path);
736 if (merged_fd != -1 && close(merged_fd) == -1 && err == NULL)
737 err = got_error_from_errno("close");
738 if (f_merged && fclose(f_merged) == EOF && err == NULL)
739 err = got_error_from_errno("fclose");
740 free(merged_path);
741 free(base_path);
742 free(parent);
743 return err;
746 static const struct got_error *
747 update_symlink(const char *ondisk_path, const char *target_path,
748 size_t target_len)
750 /* This is not atomic but matches what 'ln -sf' does. */
751 if (unlink(ondisk_path) == -1)
752 return got_error_from_errno2("unlink", ondisk_path);
753 if (symlink(target_path, ondisk_path) == -1)
754 return got_error_from_errno3("symlink", target_path,
755 ondisk_path);
756 return NULL;
760 * Overwrite a symlink (or a regular file in case there was a "bad" symlink)
761 * in the work tree with a file that contains conflict markers and the
762 * conflicting target paths of the original version, a "derived version"
763 * of a symlink from an incoming change, and a local version of the symlink.
765 * The original versions's target path can be NULL if it is not available,
766 * such as if both derived versions added a new symlink at the same path.
768 * The incoming derived symlink target is NULL in case the incoming change
769 * has deleted this symlink.
771 static const struct got_error *
772 install_symlink_conflict(const char *deriv_target,
773 struct got_object_id *deriv_base_commit_id, const char *orig_target,
774 const char *label_orig, const char *local_target, const char *ondisk_path)
776 const struct got_error *err;
777 char *id_str = NULL, *label_deriv = NULL, *path = NULL;
778 FILE *f = NULL;
780 err = got_object_id_str(&id_str, deriv_base_commit_id);
781 if (err)
782 return got_error_from_errno("asprintf");
784 if (asprintf(&label_deriv, "%s: commit %s",
785 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
786 err = got_error_from_errno("asprintf");
787 goto done;
790 err = got_opentemp_named(&path, &f, "got-symlink-conflict", "");
791 if (err)
792 goto done;
794 if (fchmod(fileno(f), apply_umask(GOT_DEFAULT_FILE_MODE)) == -1) {
795 err = got_error_from_errno2("fchmod", path);
796 goto done;
799 if (fprintf(f, "%s %s\n%s\n%s%s%s%s%s\n%s\n%s\n",
800 GOT_DIFF_CONFLICT_MARKER_BEGIN, label_deriv,
801 deriv_target ? deriv_target : "(symlink was deleted)",
802 orig_target ? label_orig : "",
803 orig_target ? "\n" : "",
804 orig_target ? orig_target : "",
805 orig_target ? "\n" : "",
806 GOT_DIFF_CONFLICT_MARKER_SEP,
807 local_target, GOT_DIFF_CONFLICT_MARKER_END) < 0) {
808 err = got_error_from_errno2("fprintf", path);
809 goto done;
812 if (unlink(ondisk_path) == -1) {
813 err = got_error_from_errno2("unlink", ondisk_path);
814 goto done;
816 if (rename(path, ondisk_path) == -1) {
817 err = got_error_from_errno3("rename", path, ondisk_path);
818 goto done;
820 done:
821 if (f != NULL && fclose(f) == EOF && err == NULL)
822 err = got_error_from_errno2("fclose", path);
823 free(path);
824 free(id_str);
825 free(label_deriv);
826 return err;
829 /* forward declaration */
830 static const struct got_error *
831 merge_blob(int *, struct got_worktree *, struct got_blob_object *,
832 const char *, const char *, uint16_t, const char *,
833 struct got_blob_object *, struct got_object_id *,
834 struct got_repository *, got_worktree_checkout_cb, void *);
837 * Merge a symlink into the work tree, where blob_orig acts as the common
838 * ancestor, deriv_target is the link target of the first derived version,
839 * and the symlink on disk acts as the second derived version.
840 * Assume that contents of both blobs represent symlinks.
842 static const struct got_error *
843 merge_symlink(struct got_worktree *worktree,
844 struct got_blob_object *blob_orig, const char *ondisk_path,
845 const char *path, const char *label_orig, const char *deriv_target,
846 struct got_object_id *deriv_base_commit_id, struct got_repository *repo,
847 got_worktree_checkout_cb progress_cb, void *progress_arg)
849 const struct got_error *err = NULL;
850 char *ancestor_target = NULL;
851 struct stat sb;
852 ssize_t ondisk_len, deriv_len;
853 char ondisk_target[PATH_MAX];
854 int have_local_change = 0;
855 int have_incoming_change = 0;
857 if (lstat(ondisk_path, &sb) == -1)
858 return got_error_from_errno2("lstat", ondisk_path);
860 ondisk_len = readlink(ondisk_path, ondisk_target,
861 sizeof(ondisk_target));
862 if (ondisk_len == -1) {
863 err = got_error_from_errno2("readlink",
864 ondisk_path);
865 goto done;
867 ondisk_target[ondisk_len] = '\0';
869 if (blob_orig) {
870 err = got_object_blob_read_to_str(&ancestor_target, blob_orig);
871 if (err)
872 goto done;
875 if (ancestor_target == NULL ||
876 (ondisk_len != strlen(ancestor_target) ||
877 memcmp(ondisk_target, ancestor_target, ondisk_len) != 0))
878 have_local_change = 1;
880 deriv_len = strlen(deriv_target);
881 if (ancestor_target == NULL ||
882 (deriv_len != strlen(ancestor_target) ||
883 memcmp(deriv_target, ancestor_target, deriv_len) != 0))
884 have_incoming_change = 1;
886 if (!have_local_change && !have_incoming_change) {
887 if (ancestor_target) {
888 /* Both sides made the same change. */
889 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
890 path);
891 } else if (deriv_len == ondisk_len &&
892 memcmp(ondisk_target, deriv_target, deriv_len) == 0) {
893 /* Both sides added the same symlink. */
894 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
895 path);
896 } else {
897 /* Both sides added symlinks which don't match. */
898 err = install_symlink_conflict(deriv_target,
899 deriv_base_commit_id, ancestor_target,
900 label_orig, ondisk_target, ondisk_path);
901 if (err)
902 goto done;
903 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
904 path);
906 } else if (!have_local_change && have_incoming_change) {
907 /* Apply the incoming change. */
908 err = update_symlink(ondisk_path, deriv_target,
909 strlen(deriv_target));
910 if (err)
911 goto done;
912 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
913 } else if (have_local_change && have_incoming_change) {
914 if (deriv_len == ondisk_len &&
915 memcmp(deriv_target, ondisk_target, deriv_len) == 0) {
916 /* Both sides made the same change. */
917 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
918 path);
919 } else {
920 err = install_symlink_conflict(deriv_target,
921 deriv_base_commit_id, ancestor_target, label_orig,
922 ondisk_target, ondisk_path);
923 if (err)
924 goto done;
925 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
926 path);
930 done:
931 free(ancestor_target);
932 return err;
935 static const struct got_error *
936 dump_symlink_target_path_to_file(FILE **outfile, const char *ondisk_path)
938 const struct got_error *err = NULL;
939 char target_path[PATH_MAX];
940 ssize_t target_len;
941 size_t n;
942 FILE *f;
944 *outfile = NULL;
946 f = got_opentemp();
947 if (f == NULL)
948 return got_error_from_errno("got_opentemp");
949 target_len = readlink(ondisk_path, target_path, sizeof(target_path));
950 if (target_len == -1) {
951 err = got_error_from_errno2("readlink", ondisk_path);
952 goto done;
954 n = fwrite(target_path, 1, target_len, f);
955 if (n != target_len) {
956 err = got_ferror(f, GOT_ERR_IO);
957 goto done;
959 if (fflush(f) == EOF) {
960 err = got_error_from_errno("fflush");
961 goto done;
963 if (fseek(f, 0L, SEEK_SET) == -1) {
964 err = got_ferror(f, GOT_ERR_IO);
965 goto done;
967 done:
968 if (err)
969 fclose(f);
970 else
971 *outfile = f;
972 return err;
976 * Perform a 3-way merge where blob_orig acts as the common ancestor,
977 * blob_deriv acts as the first derived version, and the file on disk
978 * acts as the second derived version.
980 static const struct got_error *
981 merge_blob(int *local_changes_subsumed, struct got_worktree *worktree,
982 struct got_blob_object *blob_orig, const char *ondisk_path,
983 const char *path, uint16_t st_mode, const char *label_orig,
984 struct got_blob_object *blob_deriv,
985 struct got_object_id *deriv_base_commit_id, struct got_repository *repo,
986 got_worktree_checkout_cb progress_cb, void *progress_arg)
988 const struct got_error *err = NULL;
989 FILE *f_orig = NULL, *f_deriv = NULL, *f_deriv2 = NULL;
990 char *blob_orig_path = NULL;
991 char *blob_deriv_path = NULL, *base_path = NULL, *id_str = NULL;
992 char *label_deriv = NULL, *parent = NULL;
994 *local_changes_subsumed = 0;
996 err = got_path_dirname(&parent, ondisk_path);
997 if (err)
998 return err;
1000 if (blob_orig) {
1001 if (asprintf(&base_path, "%s/got-merge-blob-orig",
1002 parent) == -1) {
1003 err = got_error_from_errno("asprintf");
1004 base_path = NULL;
1005 goto done;
1008 err = got_opentemp_named(&blob_orig_path, &f_orig,
1009 base_path, "");
1010 if (err)
1011 goto done;
1012 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_orig,
1013 blob_orig);
1014 if (err)
1015 goto done;
1016 free(base_path);
1017 } else {
1019 * No common ancestor exists. This is an "add vs add" conflict
1020 * and we simply use an empty ancestor file to make both files
1021 * appear in the merged result in their entirety.
1023 f_orig = got_opentemp();
1024 if (f_orig == NULL) {
1025 err = got_error_from_errno("got_opentemp");
1026 goto done;
1030 if (asprintf(&base_path, "%s/got-merge-blob-deriv", parent) == -1) {
1031 err = got_error_from_errno("asprintf");
1032 base_path = NULL;
1033 goto done;
1036 err = got_opentemp_named(&blob_deriv_path, &f_deriv, base_path, "");
1037 if (err)
1038 goto done;
1039 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_deriv,
1040 blob_deriv);
1041 if (err)
1042 goto done;
1044 err = got_object_id_str(&id_str, deriv_base_commit_id);
1045 if (err)
1046 goto done;
1047 if (asprintf(&label_deriv, "%s: commit %s",
1048 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
1049 err = got_error_from_errno("asprintf");
1050 goto done;
1054 * In order the run a 3-way merge with a symlink we copy the symlink's
1055 * target path into a temporary file and use that file with diff3.
1057 if (S_ISLNK(st_mode)) {
1058 err = dump_symlink_target_path_to_file(&f_deriv2, ondisk_path);
1059 if (err)
1060 goto done;
1061 } else {
1062 int fd;
1063 fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
1064 if (fd == -1) {
1065 err = got_error_from_errno2("open", ondisk_path);
1066 goto done;
1068 f_deriv2 = fdopen(fd, "r");
1069 if (f_deriv2 == NULL) {
1070 err = got_error_from_errno2("fdopen", ondisk_path);
1071 close(fd);
1072 goto done;
1076 err = merge_file(local_changes_subsumed, worktree, f_orig, f_deriv,
1077 f_deriv2, ondisk_path, path, st_mode, label_orig, label_deriv,
1078 NULL, GOT_DIFF_ALGORITHM_MYERS, repo, progress_cb, progress_arg);
1079 done:
1080 if (f_orig && fclose(f_orig) == EOF && err == NULL)
1081 err = got_error_from_errno("fclose");
1082 if (f_deriv && fclose(f_deriv) == EOF && err == NULL)
1083 err = got_error_from_errno("fclose");
1084 if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL)
1085 err = got_error_from_errno("fclose");
1086 free(base_path);
1087 if (blob_orig_path) {
1088 unlink(blob_orig_path);
1089 free(blob_orig_path);
1091 if (blob_deriv_path) {
1092 unlink(blob_deriv_path);
1093 free(blob_deriv_path);
1095 free(id_str);
1096 free(label_deriv);
1097 free(parent);
1098 return err;
1101 static const struct got_error *
1102 create_fileindex_entry(struct got_fileindex_entry **new_iep,
1103 struct got_fileindex *fileindex, struct got_object_id *base_commit_id,
1104 int wt_fd, const char *path, struct got_object_id *blob_id,
1105 int update_timestamps)
1107 const struct got_error *err = NULL;
1108 struct got_fileindex_entry *new_ie;
1110 *new_iep = NULL;
1112 err = got_fileindex_entry_alloc(&new_ie, path);
1113 if (err)
1114 return err;
1116 err = got_fileindex_entry_update(new_ie, wt_fd, path,
1117 blob_id, base_commit_id, update_timestamps);
1118 if (err)
1119 goto done;
1121 err = got_fileindex_entry_add(fileindex, new_ie);
1122 done:
1123 if (err)
1124 got_fileindex_entry_free(new_ie);
1125 else
1126 *new_iep = new_ie;
1127 return err;
1130 static mode_t
1131 get_ondisk_perms(int executable, mode_t st_mode)
1133 mode_t xbits = S_IXUSR;
1135 if (executable) {
1136 /* Map read bits to execute bits. */
1137 if (st_mode & S_IRGRP)
1138 xbits |= S_IXGRP;
1139 if (st_mode & S_IROTH)
1140 xbits |= S_IXOTH;
1141 return st_mode | xbits;
1144 return st_mode;
1147 /* forward declaration */
1148 static const struct got_error *
1149 install_blob(struct got_worktree *worktree, const char *ondisk_path,
1150 const char *path, mode_t te_mode, mode_t st_mode,
1151 struct got_blob_object *blob, int restoring_missing_file,
1152 int reverting_versioned_file, int installing_bad_symlink,
1153 int path_is_unversioned, int *update_timestamps,
1154 struct got_repository *repo,
1155 got_worktree_checkout_cb progress_cb, void *progress_arg);
1158 * This function assumes that the provided symlink target points at a
1159 * safe location in the work tree!
1161 static const struct got_error *
1162 replace_existing_symlink(int *did_something, const char *ondisk_path,
1163 const char *target_path, size_t target_len)
1165 const struct got_error *err = NULL;
1166 ssize_t elen;
1167 char etarget[PATH_MAX];
1168 int fd;
1170 *did_something = 0;
1173 * "Bad" symlinks (those pointing outside the work tree or into the
1174 * .got directory) are installed in the work tree as a regular file
1175 * which contains the bad symlink target path.
1176 * The new symlink target has already been checked for safety by our
1177 * caller. If we can successfully open a regular file then we simply
1178 * replace this file with a symlink below.
1180 fd = open(ondisk_path, O_RDWR | O_EXCL | O_NOFOLLOW | O_CLOEXEC);
1181 if (fd == -1) {
1182 if (!got_err_open_nofollow_on_symlink())
1183 return got_error_from_errno2("open", ondisk_path);
1185 /* We are updating an existing on-disk symlink. */
1186 elen = readlink(ondisk_path, etarget, sizeof(etarget));
1187 if (elen == -1)
1188 return got_error_from_errno2("readlink", ondisk_path);
1190 if (elen == target_len &&
1191 memcmp(etarget, target_path, target_len) == 0)
1192 return NULL; /* nothing to do */
1195 *did_something = 1;
1196 err = update_symlink(ondisk_path, target_path, target_len);
1197 if (fd != -1 && close(fd) == -1 && err == NULL)
1198 err = got_error_from_errno2("close", ondisk_path);
1199 return err;
1202 static const struct got_error *
1203 is_bad_symlink_target(int *is_bad_symlink, const char *target_path,
1204 size_t target_len, const char *ondisk_path, const char *wtroot_path,
1205 const char *meta_dir)
1207 const struct got_error *err = NULL;
1208 char canonpath[PATH_MAX];
1209 char *path_got = NULL;
1211 *is_bad_symlink = 0;
1213 if (target_len >= sizeof(canonpath)) {
1214 *is_bad_symlink = 1;
1215 return NULL;
1219 * We do not use realpath(3) to resolve the symlink's target
1220 * path because we don't want to resolve symlinks recursively.
1221 * Instead we make the path absolute and then canonicalize it.
1222 * Relative symlink target lookup should begin at the directory
1223 * in which the blob object is being installed.
1225 if (!got_path_is_absolute(target_path)) {
1226 char *abspath, *parent;
1227 err = got_path_dirname(&parent, ondisk_path);
1228 if (err)
1229 return err;
1230 if (asprintf(&abspath, "%s/%s", parent, target_path) == -1) {
1231 free(parent);
1232 return got_error_from_errno("asprintf");
1234 free(parent);
1235 if (strlen(abspath) >= sizeof(canonpath)) {
1236 err = got_error_path(abspath, GOT_ERR_BAD_PATH);
1237 free(abspath);
1238 return err;
1240 err = got_canonpath(abspath, canonpath, sizeof(canonpath));
1241 free(abspath);
1242 if (err)
1243 return err;
1244 } else {
1245 err = got_canonpath(target_path, canonpath, sizeof(canonpath));
1246 if (err)
1247 return err;
1250 /* Only allow symlinks pointing at paths within the work tree. */
1251 if (!got_path_is_child(canonpath, wtroot_path, strlen(wtroot_path))) {
1252 *is_bad_symlink = 1;
1253 return NULL;
1256 /* Do not allow symlinks pointing into the meta directory. */
1257 if (asprintf(&path_got, "%s/%s", wtroot_path, meta_dir) == -1)
1258 return got_error_from_errno("asprintf");
1259 if (got_path_is_child(canonpath, path_got, strlen(path_got)))
1260 *is_bad_symlink = 1;
1262 free(path_got);
1263 return NULL;
1266 static const struct got_error *
1267 install_symlink(int *is_bad_symlink, struct got_worktree *worktree,
1268 const char *ondisk_path, const char *path, struct got_blob_object *blob,
1269 int restoring_missing_file, int reverting_versioned_file,
1270 int path_is_unversioned, int allow_bad_symlinks,
1271 struct got_repository *repo,
1272 got_worktree_checkout_cb progress_cb, void *progress_arg)
1274 const struct got_error *err = NULL;
1275 char target_path[PATH_MAX];
1276 size_t len, target_len = 0;
1277 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1278 size_t hdrlen = got_object_blob_get_hdrlen(blob);
1280 *is_bad_symlink = 0;
1283 * Blob object content specifies the target path of the link.
1284 * If a symbolic link cannot be installed we instead create
1285 * a regular file which contains the link target path stored
1286 * in the blob object.
1288 do {
1289 err = got_object_blob_read_block(&len, blob);
1290 if (err)
1291 return err;
1293 if (len + target_len >= sizeof(target_path)) {
1294 /* Path too long; install as a regular file. */
1295 *is_bad_symlink = 1;
1296 got_object_blob_rewind(blob);
1297 return install_blob(worktree, ondisk_path, path,
1298 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1299 restoring_missing_file, reverting_versioned_file,
1300 1, path_is_unversioned, NULL, repo, progress_cb,
1301 progress_arg);
1303 if (len > 0) {
1304 /* Skip blob object header first time around. */
1305 memcpy(target_path + target_len, buf + hdrlen,
1306 len - hdrlen);
1307 target_len += len - hdrlen;
1308 hdrlen = 0;
1310 } while (len != 0);
1311 target_path[target_len] = '\0';
1313 err = is_bad_symlink_target(is_bad_symlink, target_path, target_len,
1314 ondisk_path, worktree->root_path, worktree->meta_dir);
1315 if (err)
1316 return err;
1318 if (*is_bad_symlink && !allow_bad_symlinks) {
1319 /* install as a regular file */
1320 got_object_blob_rewind(blob);
1321 err = install_blob(worktree, ondisk_path, path,
1322 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1323 restoring_missing_file, reverting_versioned_file, 1,
1324 path_is_unversioned, NULL, repo,
1325 progress_cb, progress_arg);
1326 return err;
1329 if (symlink(target_path, ondisk_path) == -1) {
1330 if (errno == EEXIST) {
1331 int symlink_replaced;
1332 if (path_is_unversioned) {
1333 err = (*progress_cb)(progress_arg,
1334 GOT_STATUS_UNVERSIONED, path);
1335 return err;
1337 err = replace_existing_symlink(&symlink_replaced,
1338 ondisk_path, target_path, target_len);
1339 if (err)
1340 return err;
1341 if (progress_cb) {
1342 if (symlink_replaced) {
1343 err = (*progress_cb)(progress_arg,
1344 reverting_versioned_file ?
1345 GOT_STATUS_REVERT :
1346 GOT_STATUS_UPDATE, path);
1347 } else {
1348 err = (*progress_cb)(progress_arg,
1349 GOT_STATUS_EXISTS, path);
1352 return err; /* Nothing else to do. */
1355 if (errno == ENOENT) {
1356 char *parent;
1357 err = got_path_dirname(&parent, ondisk_path);
1358 if (err)
1359 return err;
1360 err = got_path_mkdir(parent);
1361 free(parent);
1362 if (err)
1363 return err;
1365 * Retry, and fall through to error handling
1366 * below if this second attempt fails.
1368 if (symlink(target_path, ondisk_path) != -1) {
1369 err = NULL; /* success */
1370 if (progress_cb) {
1371 err = (*progress_cb)(progress_arg,
1372 reverting_versioned_file ?
1373 GOT_STATUS_REVERT : GOT_STATUS_ADD,
1374 path);
1376 return err;
1380 /* Handle errors from first or second creation attempt. */
1381 if (errno == ENAMETOOLONG) {
1382 /* bad target path; install as a regular file */
1383 *is_bad_symlink = 1;
1384 got_object_blob_rewind(blob);
1385 err = install_blob(worktree, ondisk_path, path,
1386 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1387 restoring_missing_file, reverting_versioned_file, 1,
1388 path_is_unversioned, NULL, repo,
1389 progress_cb, progress_arg);
1390 } else if (errno == ENOTDIR) {
1391 err = got_error_path(ondisk_path,
1392 GOT_ERR_FILE_OBSTRUCTED);
1393 } else {
1394 err = got_error_from_errno3("symlink",
1395 target_path, ondisk_path);
1397 } else if (progress_cb)
1398 err = (*progress_cb)(progress_arg, reverting_versioned_file ?
1399 GOT_STATUS_REVERT : GOT_STATUS_ADD, path);
1400 return err;
1403 static const struct got_error *
1404 install_blob(struct got_worktree *worktree, const char *ondisk_path,
1405 const char *path, mode_t te_mode, mode_t st_mode,
1406 struct got_blob_object *blob, int restoring_missing_file,
1407 int reverting_versioned_file, int installing_bad_symlink,
1408 int path_is_unversioned, int *update_timestamps,
1409 struct got_repository *repo,
1410 got_worktree_checkout_cb progress_cb, void *progress_arg)
1412 const struct got_error *err = NULL;
1413 int fd = -1;
1414 size_t len, hdrlen;
1415 int update = 0;
1416 char *tmppath = NULL;
1417 mode_t mode;
1419 if (update_timestamps)
1420 *update_timestamps = 1;
1422 mode = get_ondisk_perms(te_mode & S_IXUSR, GOT_DEFAULT_FILE_MODE);
1423 fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW |
1424 O_CLOEXEC, mode);
1425 if (fd == -1) {
1426 if (errno == ENOENT || errno == ENOTDIR) {
1427 char *parent;
1428 err = got_path_dirname(&parent, path);
1429 if (err)
1430 return err;
1431 err = add_dir_on_disk(worktree, parent);
1432 if (err && err->code == GOT_ERR_FILE_OBSTRUCTED)
1433 err = got_error_path(path, err->code);
1434 free(parent);
1435 if (err)
1436 return err;
1437 fd = open(ondisk_path,
1438 O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
1439 mode);
1440 if (fd == -1)
1441 return got_error_from_errno2("open",
1442 ondisk_path);
1443 } else if (errno == EEXIST) {
1444 if (path_is_unversioned) {
1445 if (update_timestamps)
1446 *update_timestamps = 0;
1447 err = (*progress_cb)(progress_arg,
1448 GOT_STATUS_EXISTS, path);
1449 goto done;
1451 if (!(S_ISLNK(st_mode) && S_ISREG(te_mode)) &&
1452 !S_ISREG(st_mode) && !installing_bad_symlink) {
1453 /* TODO file is obstructed; do something */
1454 err = got_error_path(ondisk_path,
1455 GOT_ERR_FILE_OBSTRUCTED);
1456 goto done;
1457 } else {
1458 err = got_opentemp_named_fd(&tmppath, &fd,
1459 ondisk_path, "");
1460 if (err)
1461 goto done;
1462 update = 1;
1464 if (fchmod(fd, apply_umask(mode)) == -1) {
1465 err = got_error_from_errno2("fchmod",
1466 tmppath);
1467 goto done;
1470 } else
1471 return got_error_from_errno2("open", ondisk_path);
1474 if (progress_cb) {
1475 if (restoring_missing_file)
1476 err = (*progress_cb)(progress_arg, GOT_STATUS_MISSING,
1477 path);
1478 else if (reverting_versioned_file)
1479 err = (*progress_cb)(progress_arg, GOT_STATUS_REVERT,
1480 path);
1481 else
1482 err = (*progress_cb)(progress_arg,
1483 update ? GOT_STATUS_UPDATE : GOT_STATUS_ADD, path);
1484 if (err)
1485 goto done;
1488 hdrlen = got_object_blob_get_hdrlen(blob);
1489 do {
1490 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1491 err = got_object_blob_read_block(&len, blob);
1492 if (err)
1493 break;
1494 if (len > 0) {
1495 /* Skip blob object header first time around. */
1496 ssize_t outlen = write(fd, buf + hdrlen, len - hdrlen);
1497 if (outlen == -1) {
1498 err = got_error_from_errno("write");
1499 goto done;
1500 } else if (outlen != len - hdrlen) {
1501 err = got_error(GOT_ERR_IO);
1502 goto done;
1504 hdrlen = 0;
1506 } while (len != 0);
1508 if (fsync(fd) != 0) {
1509 err = got_error_from_errno("fsync");
1510 goto done;
1513 if (update) {
1514 if (S_ISLNK(st_mode) && unlink(ondisk_path) == -1) {
1515 err = got_error_from_errno2("unlink", ondisk_path);
1516 goto done;
1518 if (rename(tmppath, ondisk_path) != 0) {
1519 err = got_error_from_errno3("rename", tmppath,
1520 ondisk_path);
1521 goto done;
1523 free(tmppath);
1524 tmppath = NULL;
1527 done:
1528 if (fd != -1 && close(fd) == -1 && err == NULL)
1529 err = got_error_from_errno("close");
1530 if (tmppath != NULL && unlink(tmppath) == -1 && err == NULL)
1531 err = got_error_from_errno2("unlink", tmppath);
1532 free(tmppath);
1533 return err;
1537 * Upgrade STATUS_MODIFY to STATUS_CONFLICT if a
1538 * conflict marker is found in newly added lines only.
1540 static const struct got_error *
1541 get_modified_file_content_status(unsigned char *status,
1542 struct got_blob_object *blob, const char *path, struct stat *sb,
1543 FILE *ondisk_file)
1545 const struct got_error *err, *free_err;
1546 const char *markers[3] = {
1547 GOT_DIFF_CONFLICT_MARKER_BEGIN,
1548 GOT_DIFF_CONFLICT_MARKER_SEP,
1549 GOT_DIFF_CONFLICT_MARKER_END
1551 FILE *f1 = NULL;
1552 struct got_diffreg_result *diffreg_result = NULL;
1553 struct diff_result *r;
1554 int nchunks_parsed, n, i = 0, ln = 0;
1555 char *line = NULL;
1556 size_t linesize = 0;
1557 ssize_t linelen;
1559 if (*status != GOT_STATUS_MODIFY)
1560 return NULL;
1562 f1 = got_opentemp();
1563 if (f1 == NULL)
1564 return got_error_from_errno("got_opentemp");
1566 if (blob) {
1567 got_object_blob_rewind(blob);
1568 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob);
1569 if (err)
1570 goto done;
1573 err = got_diff_files(&diffreg_result, f1, 1, NULL, ondisk_file,
1574 1, NULL, 0, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS);
1575 if (err)
1576 goto done;
1578 r = diffreg_result->result;
1580 for (n = 0; n < r->chunks.len; n += nchunks_parsed) {
1581 struct diff_chunk *c;
1582 struct diff_chunk_context cc = {};
1583 off_t pos;
1586 * We can optimise a little by advancing straight
1587 * to the next chunk if this one has no added lines.
1589 c = diff_chunk_get(r, n);
1591 if (diff_chunk_type(c) != CHUNK_PLUS) {
1592 nchunks_parsed = 1;
1593 continue; /* removed or unchanged lines */
1596 pos = diff_chunk_get_right_start_pos(c);
1597 if (fseek(ondisk_file, pos, SEEK_SET) == -1) {
1598 err = got_ferror(ondisk_file, GOT_ERR_IO);
1599 goto done;
1602 diff_chunk_context_load_change(&cc, &nchunks_parsed, r, n, 0);
1603 ln = cc.right.start;
1605 while (ln < cc.right.end) {
1606 linelen = getline(&line, &linesize, ondisk_file);
1607 if (linelen == -1) {
1608 if (feof(ondisk_file))
1609 break;
1610 err = got_ferror(ondisk_file, GOT_ERR_IO);
1611 break;
1614 if (line && strncmp(line, markers[i],
1615 strlen(markers[i])) == 0) {
1616 if (strcmp(markers[i],
1617 GOT_DIFF_CONFLICT_MARKER_END) == 0) {
1618 *status = GOT_STATUS_CONFLICT;
1619 goto done;
1620 } else
1621 i++;
1623 ++ln;
1627 done:
1628 free(line);
1629 if (f1 != NULL && fclose(f1) == EOF && err == NULL)
1630 err = got_error_from_errno("fclose");
1631 free_err = got_diffreg_result_free(diffreg_result);
1632 if (err == NULL)
1633 err = free_err;
1635 return err;
1638 static int
1639 xbit_differs(struct got_fileindex_entry *ie, uint16_t st_mode)
1641 mode_t ie_mode = got_fileindex_perms_to_st(ie);
1642 return ((ie_mode & S_IXUSR) != (st_mode & S_IXUSR));
1645 static int
1646 stat_info_differs(struct got_fileindex_entry *ie, struct stat *sb)
1648 return !(ie->ctime_sec == sb->st_ctim.tv_sec &&
1649 ie->ctime_nsec == sb->st_ctim.tv_nsec &&
1650 ie->mtime_sec == sb->st_mtim.tv_sec &&
1651 ie->mtime_nsec == sb->st_mtim.tv_nsec &&
1652 ie->size == (sb->st_size & 0xffffffff) &&
1653 !xbit_differs(ie, sb->st_mode));
1656 static unsigned char
1657 get_staged_status(struct got_fileindex_entry *ie)
1659 switch (got_fileindex_entry_stage_get(ie)) {
1660 case GOT_FILEIDX_STAGE_ADD:
1661 return GOT_STATUS_ADD;
1662 case GOT_FILEIDX_STAGE_DELETE:
1663 return GOT_STATUS_DELETE;
1664 case GOT_FILEIDX_STAGE_MODIFY:
1665 return GOT_STATUS_MODIFY;
1666 default:
1667 return GOT_STATUS_NO_CHANGE;
1671 static const struct got_error *
1672 get_symlink_modification_status(unsigned char *status,
1673 struct got_fileindex_entry *ie, const char *abspath,
1674 int dirfd, const char *de_name, struct got_blob_object *blob)
1676 const struct got_error *err = NULL;
1677 char target_path[PATH_MAX];
1678 char etarget[PATH_MAX];
1679 ssize_t elen;
1680 size_t len, target_len = 0;
1681 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1682 size_t hdrlen = got_object_blob_get_hdrlen(blob);
1684 *status = GOT_STATUS_NO_CHANGE;
1686 /* Blob object content specifies the target path of the link. */
1687 do {
1688 err = got_object_blob_read_block(&len, blob);
1689 if (err)
1690 return err;
1691 if (len + target_len >= sizeof(target_path)) {
1693 * Should not happen. The blob contents were OK
1694 * when this symlink was installed.
1696 return got_error(GOT_ERR_NO_SPACE);
1698 if (len > 0) {
1699 /* Skip blob object header first time around. */
1700 memcpy(target_path + target_len, buf + hdrlen,
1701 len - hdrlen);
1702 target_len += len - hdrlen;
1703 hdrlen = 0;
1705 } while (len != 0);
1706 target_path[target_len] = '\0';
1708 if (dirfd != -1) {
1709 elen = readlinkat(dirfd, de_name, etarget, sizeof(etarget));
1710 if (elen == -1)
1711 return got_error_from_errno2("readlinkat", abspath);
1712 } else {
1713 elen = readlink(abspath, etarget, sizeof(etarget));
1714 if (elen == -1)
1715 return got_error_from_errno2("readlink", abspath);
1718 if (elen != target_len || memcmp(etarget, target_path, target_len) != 0)
1719 *status = GOT_STATUS_MODIFY;
1721 return NULL;
1724 static const struct got_error *
1725 get_file_status(unsigned char *status, struct stat *sb,
1726 struct got_fileindex_entry *ie, const char *abspath,
1727 int dirfd, const char *de_name, struct got_repository *repo)
1729 const struct got_error *err = NULL;
1730 struct got_object_id id;
1731 size_t hdrlen;
1732 int fd = -1, fd1 = -1;
1733 FILE *f = NULL;
1734 uint8_t fbuf[8192];
1735 struct got_blob_object *blob = NULL;
1736 size_t flen, blen;
1737 unsigned char staged_status;
1739 staged_status = get_staged_status(ie);
1740 *status = GOT_STATUS_NO_CHANGE;
1741 memset(sb, 0, sizeof(*sb));
1744 * Whenever the caller provides a directory descriptor and a
1745 * directory entry name for the file, use them! This prevents
1746 * race conditions if filesystem paths change beneath our feet.
1748 if (dirfd != -1) {
1749 if (fstatat(dirfd, de_name, sb, AT_SYMLINK_NOFOLLOW) == -1) {
1750 if (errno == ENOENT) {
1751 if (got_fileindex_entry_has_file_on_disk(ie))
1752 *status = GOT_STATUS_MISSING;
1753 else
1754 *status = GOT_STATUS_DELETE;
1755 goto done;
1757 err = got_error_from_errno2("fstatat", abspath);
1758 goto done;
1760 } else {
1761 fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
1762 if (fd == -1 && errno != ENOENT &&
1763 !got_err_open_nofollow_on_symlink())
1764 return got_error_from_errno2("open", abspath);
1765 else if (fd == -1 && got_err_open_nofollow_on_symlink()) {
1766 if (lstat(abspath, sb) == -1)
1767 return got_error_from_errno2("lstat", abspath);
1768 } else if (fd == -1 || fstat(fd, sb) == -1) {
1769 if (errno == ENOENT) {
1770 if (got_fileindex_entry_has_file_on_disk(ie))
1771 *status = GOT_STATUS_MISSING;
1772 else
1773 *status = GOT_STATUS_DELETE;
1774 goto done;
1776 err = got_error_from_errno2("fstat", abspath);
1777 goto done;
1781 if (!S_ISREG(sb->st_mode) && !S_ISLNK(sb->st_mode)) {
1782 *status = GOT_STATUS_OBSTRUCTED;
1783 goto done;
1786 if (!got_fileindex_entry_has_file_on_disk(ie)) {
1787 *status = GOT_STATUS_DELETE;
1788 goto done;
1789 } else if (!got_fileindex_entry_has_blob(ie) &&
1790 staged_status != GOT_STATUS_ADD) {
1791 *status = GOT_STATUS_ADD;
1792 goto done;
1795 if (!stat_info_differs(ie, sb))
1796 goto done;
1798 if (S_ISLNK(sb->st_mode) &&
1799 got_fileindex_entry_filetype_get(ie) != GOT_FILEIDX_MODE_SYMLINK) {
1800 *status = GOT_STATUS_MODIFY;
1801 goto done;
1804 if (staged_status == GOT_STATUS_MODIFY ||
1805 staged_status == GOT_STATUS_ADD)
1806 got_fileindex_entry_get_staged_blob_id(&id, ie);
1807 else
1808 got_fileindex_entry_get_blob_id(&id, ie);
1810 fd1 = got_opentempfd();
1811 if (fd1 == -1) {
1812 err = got_error_from_errno("got_opentempfd");
1813 goto done;
1815 err = got_object_open_as_blob(&blob, repo, &id, sizeof(fbuf), fd1);
1816 if (err)
1817 goto done;
1819 if (S_ISLNK(sb->st_mode)) {
1820 err = get_symlink_modification_status(status, ie,
1821 abspath, dirfd, de_name, blob);
1822 goto done;
1825 if (dirfd != -1) {
1826 fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
1827 if (fd == -1) {
1828 err = got_error_from_errno2("openat", abspath);
1829 goto done;
1833 f = fdopen(fd, "r");
1834 if (f == NULL) {
1835 err = got_error_from_errno2("fdopen", abspath);
1836 goto done;
1838 fd = -1;
1839 hdrlen = got_object_blob_get_hdrlen(blob);
1840 for (;;) {
1841 const uint8_t *bbuf = got_object_blob_get_read_buf(blob);
1842 err = got_object_blob_read_block(&blen, blob);
1843 if (err)
1844 goto done;
1845 /* Skip length of blob object header first time around. */
1846 flen = fread(fbuf, 1, sizeof(fbuf) - hdrlen, f);
1847 if (flen == 0 && ferror(f)) {
1848 err = got_error_from_errno("fread");
1849 goto done;
1851 if (blen - hdrlen == 0) {
1852 if (flen != 0)
1853 *status = GOT_STATUS_MODIFY;
1854 break;
1855 } else if (flen == 0) {
1856 if (blen - hdrlen != 0)
1857 *status = GOT_STATUS_MODIFY;
1858 break;
1859 } else if (blen - hdrlen == flen) {
1860 /* Skip blob object header first time around. */
1861 if (memcmp(bbuf + hdrlen, fbuf, flen) != 0) {
1862 *status = GOT_STATUS_MODIFY;
1863 break;
1865 } else {
1866 *status = GOT_STATUS_MODIFY;
1867 break;
1869 hdrlen = 0;
1872 if (*status == GOT_STATUS_MODIFY) {
1873 rewind(f);
1874 err = get_modified_file_content_status(status, blob, ie->path,
1875 sb, f);
1876 } else if (xbit_differs(ie, sb->st_mode))
1877 *status = GOT_STATUS_MODE_CHANGE;
1878 done:
1879 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
1880 err = got_error_from_errno("close");
1881 if (blob)
1882 got_object_blob_close(blob);
1883 if (f != NULL && fclose(f) == EOF && err == NULL)
1884 err = got_error_from_errno2("fclose", abspath);
1885 if (fd != -1 && close(fd) == -1 && err == NULL)
1886 err = got_error_from_errno2("close", abspath);
1887 return err;
1891 * Update timestamps in the file index if a file is unmodified and
1892 * we had to run a full content comparison to find out.
1894 static const struct got_error *
1895 sync_timestamps(int wt_fd, const char *path, unsigned char status,
1896 struct got_fileindex_entry *ie, struct stat *sb)
1898 if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb))
1899 return got_fileindex_entry_update(ie, wt_fd, path,
1900 &ie->blob, &ie->commit, 1);
1902 return NULL;
1905 static const struct got_error *remove_ondisk_file(const char *, const char *);
1907 static const struct got_error *
1908 update_blob(struct got_worktree *worktree,
1909 struct got_fileindex *fileindex, struct got_fileindex_entry *ie,
1910 struct got_tree_entry *te, const char *path,
1911 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
1912 void *progress_arg)
1914 const struct got_error *err = NULL;
1915 struct got_blob_object *blob = NULL;
1916 char *ondisk_path = NULL;
1917 unsigned char status = GOT_STATUS_NO_CHANGE;
1918 struct stat sb;
1919 int fd1 = -1, fd2 = -1;
1920 int update_timestamps = 0;
1922 if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, path) == -1)
1923 return got_error_from_errno("asprintf");
1925 if (ie) {
1926 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE) {
1927 err = got_error_path(ie->path, GOT_ERR_FILE_STAGED);
1928 goto done;
1930 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
1931 repo);
1932 if (err)
1933 goto done;
1934 if (status == GOT_STATUS_MISSING || status == GOT_STATUS_DELETE)
1935 sb.st_mode = got_fileindex_perms_to_st(ie);
1936 } else {
1937 if (stat(ondisk_path, &sb) == -1) {
1938 if (errno != ENOENT && errno != ENOTDIR) {
1939 err = got_error_from_errno2("stat",
1940 ondisk_path);
1941 goto done;
1943 sb.st_mode = GOT_DEFAULT_FILE_MODE;
1944 status = GOT_STATUS_UNVERSIONED;
1945 } else {
1946 if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode))
1947 status = GOT_STATUS_UNVERSIONED;
1948 else
1949 status = GOT_STATUS_OBSTRUCTED;
1953 if (status == GOT_STATUS_OBSTRUCTED) {
1954 if (ie)
1955 got_fileindex_entry_mark_skipped(ie);
1956 err = (*progress_cb)(progress_arg, status, path);
1957 goto done;
1959 if (status == GOT_STATUS_CONFLICT) {
1960 if (ie)
1961 got_fileindex_entry_mark_skipped(ie);
1962 err = (*progress_cb)(progress_arg, GOT_STATUS_CANNOT_UPDATE,
1963 path);
1964 goto done;
1967 if (S_ISDIR(te->mode)) { /* file changing into a directory */
1968 if (status == GOT_STATUS_UNVERSIONED) {
1969 err = (*progress_cb)(progress_arg, status, path);
1970 } else if (status != GOT_STATUS_NO_CHANGE &&
1971 status != GOT_STATUS_DELETE &&
1972 status != GOT_STATUS_NONEXISTENT &&
1973 status != GOT_STATUS_MISSING) {
1974 err = (*progress_cb)(progress_arg,
1975 GOT_STATUS_CANNOT_DELETE, path);
1976 } else if (ie) {
1977 if (status != GOT_STATUS_DELETE &&
1978 status != GOT_STATUS_NONEXISTENT &&
1979 status != GOT_STATUS_MISSING) {
1980 err = remove_ondisk_file(worktree->root_path,
1981 ie->path);
1982 if (err && !(err->code == GOT_ERR_ERRNO &&
1983 errno == ENOENT))
1984 goto done;
1986 got_fileindex_entry_remove(fileindex, ie);
1987 err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE,
1988 ie->path);
1990 goto done; /* nothing else to do */
1993 if (ie && status != GOT_STATUS_MISSING && S_ISREG(sb.st_mode) &&
1994 (S_ISLNK(te->mode) ||
1995 (te->mode & S_IXUSR) == (sb.st_mode & S_IXUSR))) {
1997 * This is a regular file or an installed bad symlink.
1998 * If the file index indicates that this file is already
1999 * up-to-date with respect to the repository we can skip
2000 * updating contents of this file.
2002 if (got_fileindex_entry_has_commit(ie) &&
2003 got_object_id_cmp(&ie->commit,
2004 worktree->base_commit_id) == 0) {
2005 /* Same commit. */
2006 err = sync_timestamps(worktree->root_fd,
2007 path, status, ie, &sb);
2008 if (err)
2009 goto done;
2010 err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
2011 path);
2012 goto done;
2014 if (got_fileindex_entry_has_blob(ie) &&
2015 got_object_id_cmp(&ie->blob, &te->id) == 0) {
2016 /* Different commit but the same blob. */
2017 if (got_fileindex_entry_has_commit(ie)) {
2018 /* Update the base commit ID of this file. */
2019 memcpy(&ie->commit, worktree->base_commit_id,
2020 sizeof(ie->commit));
2022 err = sync_timestamps(worktree->root_fd,
2023 path, status, ie, &sb);
2024 if (err)
2025 goto done;
2026 err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
2027 path);
2028 goto done;
2032 fd1 = got_opentempfd();
2033 if (fd1 == -1) {
2034 err = got_error_from_errno("got_opentempfd");
2035 goto done;
2037 err = got_object_open_as_blob(&blob, repo, &te->id, 8192, fd1);
2038 if (err)
2039 goto done;
2041 if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_ADD) {
2042 struct got_blob_object *blob2 = NULL;
2043 char *label_orig = NULL;
2044 if (got_fileindex_entry_has_blob(ie)) {
2045 fd2 = got_opentempfd();
2046 if (fd2 == -1) {
2047 err = got_error_from_errno("got_opentempfd");
2048 goto done;
2050 struct got_object_id id2;
2051 got_fileindex_entry_get_blob_id(&id2, ie);
2052 err = got_object_open_as_blob(&blob2, repo, &id2, 8192,
2053 fd2);
2054 if (err)
2055 goto done;
2057 if (got_fileindex_entry_has_commit(ie)) {
2058 char id_str[GOT_HASH_DIGEST_STRING_MAXLEN];
2060 if (got_hash_digest_to_str(ie->commit.hash, id_str,
2061 sizeof(id_str), ie->commit.algo) == NULL) {
2062 err = got_error_path(id_str,
2063 GOT_ERR_BAD_OBJ_ID_STR);
2064 goto done;
2066 if (asprintf(&label_orig, "%s: commit %s",
2067 GOT_MERGE_LABEL_BASE, id_str) == -1) {
2068 err = got_error_from_errno("asprintf");
2069 goto done;
2072 if (S_ISLNK(te->mode) && S_ISLNK(sb.st_mode)) {
2073 char *link_target;
2074 err = got_object_blob_read_to_str(&link_target, blob);
2075 if (err)
2076 goto done;
2077 err = merge_symlink(worktree, blob2, ondisk_path, path,
2078 label_orig, link_target, worktree->base_commit_id,
2079 repo, progress_cb, progress_arg);
2080 free(link_target);
2081 } else {
2082 err = merge_blob(&update_timestamps, worktree, blob2,
2083 ondisk_path, path, sb.st_mode, label_orig, blob,
2084 worktree->base_commit_id, repo,
2085 progress_cb, progress_arg);
2087 free(label_orig);
2088 if (fd2 != -1 && close(fd2) == -1 && err == NULL) {
2089 err = got_error_from_errno("close");
2090 goto done;
2092 if (blob2)
2093 got_object_blob_close(blob2);
2094 if (err)
2095 goto done;
2097 * Do not update timestamps of files with local changes.
2098 * Otherwise, a future status walk would treat them as
2099 * unmodified files again.
2101 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2102 &blob->id, worktree->base_commit_id, update_timestamps);
2103 } else if (status == GOT_STATUS_MODE_CHANGE) {
2104 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2105 &blob->id, worktree->base_commit_id, 0);
2106 } else if (status == GOT_STATUS_DELETE) {
2107 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
2108 if (err)
2109 goto done;
2110 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2111 &blob->id, worktree->base_commit_id, 0);
2112 if (err)
2113 goto done;
2114 } else {
2115 int is_bad_symlink = 0;
2116 if (S_ISLNK(te->mode)) {
2117 err = install_symlink(&is_bad_symlink, worktree,
2118 ondisk_path, path, blob,
2119 status == GOT_STATUS_MISSING, 0,
2120 status == GOT_STATUS_UNVERSIONED, 0,
2121 repo, progress_cb, progress_arg);
2122 } else {
2123 err = install_blob(worktree, ondisk_path, path,
2124 te->mode, sb.st_mode, blob,
2125 status == GOT_STATUS_MISSING, 0, 0,
2126 status == GOT_STATUS_UNVERSIONED,
2127 &update_timestamps,
2128 repo, progress_cb, progress_arg);
2130 if (err)
2131 goto done;
2133 if (ie) {
2134 err = got_fileindex_entry_update(ie,
2135 worktree->root_fd, path, &blob->id,
2136 worktree->base_commit_id, 1);
2137 } else {
2138 err = create_fileindex_entry(&ie, fileindex,
2139 worktree->base_commit_id, worktree->root_fd, path,
2140 &blob->id, update_timestamps);
2142 if (err)
2143 goto done;
2145 if (is_bad_symlink) {
2146 got_fileindex_entry_filetype_set(ie,
2147 GOT_FILEIDX_MODE_BAD_SYMLINK);
2151 if (fd1 != -1 && close(fd1) == -1 && err == NULL) {
2152 err = got_error_from_errno("close");
2153 goto done;
2155 got_object_blob_close(blob);
2156 done:
2157 free(ondisk_path);
2158 return err;
2161 static const struct got_error *
2162 remove_ondisk_file(const char *root_path, const char *path)
2164 const struct got_error *err = NULL;
2165 char *ondisk_path = NULL, *parent = NULL;
2167 if (asprintf(&ondisk_path, "%s/%s", root_path, path) == -1)
2168 return got_error_from_errno("asprintf");
2170 if (unlink(ondisk_path) == -1) {
2171 if (errno != ENOENT)
2172 err = got_error_from_errno2("unlink", ondisk_path);
2173 } else {
2174 size_t root_len = strlen(root_path);
2175 err = got_path_dirname(&parent, ondisk_path);
2176 if (err)
2177 goto done;
2178 while (got_path_cmp(parent, root_path,
2179 strlen(parent), root_len) != 0) {
2180 free(ondisk_path);
2181 ondisk_path = parent;
2182 parent = NULL;
2183 if (rmdir(ondisk_path) == -1) {
2184 if (errno != ENOTEMPTY)
2185 err = got_error_from_errno2("rmdir",
2186 ondisk_path);
2187 break;
2189 err = got_path_dirname(&parent, ondisk_path);
2190 if (err)
2191 break;
2194 done:
2195 free(ondisk_path);
2196 free(parent);
2197 return err;
2200 static const struct got_error *
2201 delete_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
2202 struct got_fileindex_entry *ie, struct got_repository *repo,
2203 got_worktree_checkout_cb progress_cb, void *progress_arg)
2205 const struct got_error *err = NULL;
2206 unsigned char status;
2207 struct stat sb;
2208 char *ondisk_path;
2210 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE)
2211 return got_error_path(ie->path, GOT_ERR_FILE_STAGED);
2213 if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, ie->path)
2214 == -1)
2215 return got_error_from_errno("asprintf");
2217 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo);
2218 if (err)
2219 goto done;
2221 if (S_ISLNK(sb.st_mode) && status != GOT_STATUS_NO_CHANGE) {
2222 char ondisk_target[PATH_MAX];
2223 ssize_t ondisk_len = readlink(ondisk_path, ondisk_target,
2224 sizeof(ondisk_target));
2225 if (ondisk_len == -1) {
2226 err = got_error_from_errno2("readlink", ondisk_path);
2227 goto done;
2229 ondisk_target[ondisk_len] = '\0';
2230 err = install_symlink_conflict(NULL, worktree->base_commit_id,
2231 NULL, NULL, /* XXX pass common ancestor info? */
2232 ondisk_target, ondisk_path);
2233 if (err)
2234 goto done;
2235 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
2236 ie->path);
2237 goto done;
2240 if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_CONFLICT ||
2241 status == GOT_STATUS_ADD) {
2242 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, ie->path);
2243 if (err)
2244 goto done;
2246 * Preserve the working file and change the deleted blob's
2247 * entry into a schedule-add entry.
2249 err = got_fileindex_entry_update(ie, worktree->root_fd,
2250 ie->path, NULL, NULL, 0);
2251 } else {
2252 err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE, ie->path);
2253 if (err)
2254 goto done;
2255 if (status == GOT_STATUS_NO_CHANGE) {
2256 err = remove_ondisk_file(worktree->root_path, ie->path);
2257 if (err)
2258 goto done;
2260 got_fileindex_entry_remove(fileindex, ie);
2262 done:
2263 free(ondisk_path);
2264 return err;
2267 struct diff_cb_arg {
2268 struct got_fileindex *fileindex;
2269 struct got_worktree *worktree;
2270 struct got_repository *repo;
2271 got_worktree_checkout_cb progress_cb;
2272 void *progress_arg;
2273 got_cancel_cb cancel_cb;
2274 void *cancel_arg;
2277 static const struct got_error *
2278 diff_old_new(void *arg, struct got_fileindex_entry *ie,
2279 struct got_tree_entry *te, const char *parent_path)
2281 const struct got_error *err = NULL;
2282 struct diff_cb_arg *a = arg;
2284 if (a->cancel_cb) {
2285 err = a->cancel_cb(a->cancel_arg);
2286 if (err)
2287 return err;
2290 return update_blob(a->worktree, a->fileindex, ie, te,
2291 ie->path, a->repo, a->progress_cb, a->progress_arg);
2294 static const struct got_error *
2295 diff_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path)
2297 const struct got_error *err = NULL;
2298 struct diff_cb_arg *a = arg;
2300 if (a->cancel_cb) {
2301 err = a->cancel_cb(a->cancel_arg);
2302 if (err)
2303 return err;
2306 return delete_blob(a->worktree, a->fileindex, ie,
2307 a->repo, a->progress_cb, a->progress_arg);
2310 static const struct got_error *
2311 diff_new(void *arg, struct got_tree_entry *te, const char *parent_path)
2313 const struct got_error *err = NULL;
2314 struct diff_cb_arg *a = arg;
2315 char *path;
2317 if (a->cancel_cb) {
2318 err = a->cancel_cb(a->cancel_arg);
2319 if (err)
2320 return err;
2323 if (got_object_tree_entry_is_submodule(te))
2324 return NULL;
2326 if (!S_ISREG(te->mode) && !S_ISLNK(te->mode))
2327 return NULL;
2329 if (asprintf(&path, "%s%s%s", parent_path,
2330 parent_path[0] ? "/" : "", te->name)
2331 == -1)
2332 return got_error_from_errno("asprintf");
2334 err = update_blob(a->worktree, a->fileindex, NULL, te, path,
2335 a->repo, a->progress_cb, a->progress_arg);
2337 free(path);
2338 return err;
2341 const struct got_error *
2342 got_worktree_get_uuid(char **uuidstr, struct got_worktree *worktree)
2344 uint32_t uuid_status;
2346 uuid_to_string(&worktree->uuid, uuidstr, &uuid_status);
2347 if (uuid_status != uuid_s_ok) {
2348 *uuidstr = NULL;
2349 return got_error_uuid(uuid_status, "uuid_to_string");
2352 return NULL;
2355 static const struct got_error *
2356 get_ref_name(char **refname, struct got_worktree *worktree, const char *prefix)
2358 const struct got_error *err = NULL;
2359 char *uuidstr = NULL;
2361 *refname = NULL;
2363 err = got_worktree_get_uuid(&uuidstr, worktree);
2364 if (err)
2365 return err;
2367 if (asprintf(refname, "%s-%s", prefix, uuidstr) == -1) {
2368 err = got_error_from_errno("asprintf");
2369 *refname = NULL;
2371 free(uuidstr);
2372 return err;
2375 const struct got_error *
2376 got_worktree_get_logmsg_ref_name(char **refname, struct got_worktree *worktree,
2377 const char *prefix)
2379 return get_ref_name(refname, worktree, prefix);
2382 static const struct got_error *
2383 get_base_ref_name(char **refname, struct got_worktree *worktree)
2385 return get_ref_name(refname, worktree, GOT_WORKTREE_BASE_REF_PREFIX);
2388 static const struct got_error *
2389 get_rebase_tmp_ref_name(char **refname, struct got_worktree *worktree)
2391 return get_ref_name(refname, worktree,
2392 GOT_WORKTREE_REBASE_TMP_REF_PREFIX);
2395 static const struct got_error *
2396 get_newbase_symref_name(char **refname, struct got_worktree *worktree)
2398 return get_ref_name(refname, worktree, GOT_WORKTREE_NEWBASE_REF_PREFIX);
2401 static const struct got_error *
2402 get_rebase_branch_symref_name(char **refname, struct got_worktree *worktree)
2404 return get_ref_name(refname, worktree,
2405 GOT_WORKTREE_REBASE_BRANCH_REF_PREFIX);
2408 static const struct got_error *
2409 get_rebase_commit_ref_name(char **refname, struct got_worktree *worktree)
2411 return get_ref_name(refname, worktree,
2412 GOT_WORKTREE_REBASE_COMMIT_REF_PREFIX);
2415 static const struct got_error *
2416 get_histedit_tmp_ref_name(char **refname, struct got_worktree *worktree)
2418 return get_ref_name(refname, worktree,
2419 GOT_WORKTREE_HISTEDIT_TMP_REF_PREFIX);
2422 static const struct got_error *
2423 get_histedit_branch_symref_name(char **refname, struct got_worktree *worktree)
2425 return get_ref_name(refname, worktree,
2426 GOT_WORKTREE_HISTEDIT_BRANCH_REF_PREFIX);
2429 static const struct got_error *
2430 get_histedit_base_commit_ref_name(char **refname, struct got_worktree *worktree)
2432 return get_ref_name(refname, worktree,
2433 GOT_WORKTREE_HISTEDIT_BASE_COMMIT_REF_PREFIX);
2436 static const struct got_error *
2437 get_histedit_commit_ref_name(char **refname, struct got_worktree *worktree)
2439 return get_ref_name(refname, worktree,
2440 GOT_WORKTREE_HISTEDIT_COMMIT_REF_PREFIX);
2443 const struct got_error *
2444 got_worktree_get_histedit_script_path(char **path,
2445 struct got_worktree *worktree)
2447 if (asprintf(path, "%s/%s/%s", worktree->root_path,
2448 worktree->meta_dir, GOT_WORKTREE_HISTEDIT_SCRIPT) == -1) {
2449 *path = NULL;
2450 return got_error_from_errno("asprintf");
2452 return NULL;
2455 static const struct got_error *
2456 get_merge_branch_ref_name(char **refname, struct got_worktree *worktree)
2458 return get_ref_name(refname, worktree,
2459 GOT_WORKTREE_MERGE_BRANCH_REF_PREFIX);
2462 static const struct got_error *
2463 get_merge_commit_ref_name(char **refname, struct got_worktree *worktree)
2465 return get_ref_name(refname, worktree,
2466 GOT_WORKTREE_MERGE_COMMIT_REF_PREFIX);
2470 * Prevent Git's garbage collector from deleting our base commit by
2471 * setting a reference to our base commit's ID.
2473 static const struct got_error *
2474 ref_base_commit(struct got_worktree *worktree, struct got_repository *repo)
2476 const struct got_error *err = NULL;
2477 struct got_reference *ref = NULL;
2478 char *refname;
2480 err = get_base_ref_name(&refname, worktree);
2481 if (err)
2482 return err;
2484 err = got_ref_alloc(&ref, refname, worktree->base_commit_id);
2485 if (err)
2486 goto done;
2488 err = got_ref_write(ref, repo);
2489 done:
2490 free(refname);
2491 if (ref)
2492 got_ref_close(ref);
2493 return err;
2496 static const struct got_error *
2497 get_fileindex_path(char **fileindex_path, struct got_worktree *worktree)
2499 const struct got_error *err = NULL;
2501 if (asprintf(fileindex_path, "%s/%s/%s", worktree->root_path,
2502 worktree->meta_dir, GOT_WORKTREE_FILE_INDEX) == -1) {
2503 err = got_error_from_errno("asprintf");
2504 *fileindex_path = NULL;
2506 return err;
2510 static const struct got_error *
2511 open_fileindex(struct got_fileindex **fileindex, char **fileindex_path,
2512 struct got_worktree *worktree, enum got_hash_algorithm algo)
2514 const struct got_error *err = NULL;
2515 FILE *index = NULL;
2517 *fileindex = got_fileindex_alloc(algo);
2518 *fileindex_path = NULL;
2519 if (*fileindex == NULL)
2520 return got_error_from_errno("got_fileindex_alloc");
2522 err = get_fileindex_path(fileindex_path, worktree);
2523 if (err)
2524 goto done;
2526 index = fopen(*fileindex_path, "rbe");
2527 if (index == NULL) {
2528 if (errno != ENOENT)
2529 err = got_error_from_errno2("fopen", *fileindex_path);
2530 } else {
2531 err = got_fileindex_read(*fileindex, index, algo);
2532 if (fclose(index) == EOF && err == NULL)
2533 err = got_error_from_errno("fclose");
2535 done:
2536 if (err) {
2537 free(*fileindex_path);
2538 *fileindex_path = NULL;
2539 got_fileindex_free(*fileindex);
2540 *fileindex = NULL;
2542 return err;
2545 struct bump_base_commit_id_arg {
2546 struct got_object_id *base_commit_id;
2547 const char *path;
2548 size_t path_len;
2549 const char *entry_name;
2550 got_worktree_checkout_cb progress_cb;
2551 void *progress_arg;
2554 static const struct got_error *
2555 bump_base_commit_id(void *arg, struct got_fileindex_entry *ie)
2557 const struct got_error *err;
2558 struct bump_base_commit_id_arg *a = arg;
2560 if (a->entry_name) {
2561 if (strcmp(ie->path, a->path) != 0)
2562 return NULL;
2563 } else if (!got_path_is_child(ie->path, a->path, a->path_len))
2564 return NULL;
2566 if (got_fileindex_entry_was_skipped(ie))
2567 return NULL;
2569 if (got_object_id_cmp(&ie->commit, a->base_commit_id) == 0)
2570 return NULL;
2572 if (a->progress_cb) {
2573 err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_BUMP_BASE,
2574 ie->path);
2575 if (err)
2576 return err;
2578 memcpy(&ie->commit, a->base_commit_id, sizeof(ie->commit));
2579 return NULL;
2582 /* Bump base commit ID of all files within an updated part of the work tree. */
2583 static const struct got_error *
2584 bump_base_commit_id_everywhere(struct got_worktree *worktree,
2585 struct got_fileindex *fileindex,
2586 got_worktree_checkout_cb progress_cb, void *progress_arg)
2588 struct bump_base_commit_id_arg bbc_arg;
2590 bbc_arg.base_commit_id = worktree->base_commit_id;
2591 bbc_arg.entry_name = NULL;
2592 bbc_arg.path = "";
2593 bbc_arg.path_len = 0;
2594 bbc_arg.progress_cb = progress_cb;
2595 bbc_arg.progress_arg = progress_arg;
2597 return got_fileindex_for_each_entry_safe(fileindex,
2598 bump_base_commit_id, &bbc_arg);
2601 static const struct got_error *
2602 sync_fileindex(struct got_fileindex *fileindex, const char *fileindex_path)
2604 const struct got_error *err = NULL;
2605 char *new_fileindex_path = NULL;
2606 FILE *new_index = NULL;
2607 struct timespec timeout;
2609 err = got_opentemp_named(&new_fileindex_path, &new_index,
2610 fileindex_path, "");
2611 if (err)
2612 goto done;
2614 err = got_fileindex_write(fileindex, new_index);
2615 if (err)
2616 goto done;
2618 if (rename(new_fileindex_path, fileindex_path) != 0) {
2619 err = got_error_from_errno3("rename", new_fileindex_path,
2620 fileindex_path);
2621 unlink(new_fileindex_path);
2625 * Sleep for a short amount of time to ensure that files modified after
2626 * this program exits have a different time stamp from the one which
2627 * was recorded in the file index.
2629 timeout.tv_sec = 0;
2630 timeout.tv_nsec = 1;
2631 nanosleep(&timeout, NULL);
2632 done:
2633 if (new_index)
2634 fclose(new_index);
2635 free(new_fileindex_path);
2636 return err;
2639 static const struct got_error *
2640 find_tree_entry_for_checkout(int *entry_type, char **tree_relpath,
2641 struct got_object_id **tree_id, const char *wt_relpath,
2642 struct got_commit_object *base_commit, struct got_worktree *worktree,
2643 struct got_repository *repo)
2645 const struct got_error *err = NULL;
2646 struct got_object_id *id = NULL;
2647 char *in_repo_path = NULL;
2648 int is_root_wt = got_path_is_root_dir(worktree->path_prefix);
2650 *entry_type = GOT_OBJ_TYPE_ANY;
2651 *tree_relpath = NULL;
2652 *tree_id = NULL;
2654 if (wt_relpath[0] == '\0') {
2655 /* Check out all files within the work tree. */
2656 *entry_type = GOT_OBJ_TYPE_TREE;
2657 *tree_relpath = strdup("");
2658 if (*tree_relpath == NULL) {
2659 err = got_error_from_errno("strdup");
2660 goto done;
2662 err = got_object_id_by_path(tree_id, repo, base_commit,
2663 worktree->path_prefix);
2664 if (err)
2665 goto done;
2666 return NULL;
2669 /* Check out a subset of files in the work tree. */
2671 if (asprintf(&in_repo_path, "%s%s%s", worktree->path_prefix,
2672 is_root_wt ? "" : "/", wt_relpath) == -1) {
2673 err = got_error_from_errno("asprintf");
2674 goto done;
2677 err = got_object_id_by_path(&id, repo, base_commit, in_repo_path);
2678 if (err)
2679 goto done;
2681 free(in_repo_path);
2682 in_repo_path = NULL;
2684 err = got_object_get_type(entry_type, repo, id);
2685 if (err)
2686 goto done;
2688 if (*entry_type == GOT_OBJ_TYPE_BLOB) {
2689 /* Check out a single file. */
2690 if (strchr(wt_relpath, '/') == NULL) {
2691 /* Check out a single file in work tree's root dir. */
2692 in_repo_path = strdup(worktree->path_prefix);
2693 if (in_repo_path == NULL) {
2694 err = got_error_from_errno("strdup");
2695 goto done;
2697 *tree_relpath = strdup("");
2698 if (*tree_relpath == NULL) {
2699 err = got_error_from_errno("strdup");
2700 goto done;
2702 } else {
2703 /* Check out a single file in a subdirectory. */
2704 err = got_path_dirname(tree_relpath, wt_relpath);
2705 if (err)
2706 return err;
2707 if (asprintf(&in_repo_path, "%s%s%s",
2708 worktree->path_prefix, is_root_wt ? "" : "/",
2709 *tree_relpath) == -1) {
2710 err = got_error_from_errno("asprintf");
2711 goto done;
2714 err = got_object_id_by_path(tree_id, repo,
2715 base_commit, in_repo_path);
2716 } else {
2717 /* Check out all files within a subdirectory. */
2718 *tree_id = got_object_id_dup(id);
2719 if (*tree_id == NULL) {
2720 err = got_error_from_errno("got_object_id_dup");
2721 goto done;
2723 *tree_relpath = strdup(wt_relpath);
2724 if (*tree_relpath == NULL) {
2725 err = got_error_from_errno("strdup");
2726 goto done;
2729 done:
2730 free(id);
2731 free(in_repo_path);
2732 if (err) {
2733 *entry_type = GOT_OBJ_TYPE_ANY;
2734 free(*tree_relpath);
2735 *tree_relpath = NULL;
2736 free(*tree_id);
2737 *tree_id = NULL;
2739 return err;
2742 static const struct got_error *
2743 checkout_files(struct got_worktree *worktree, struct got_fileindex *fileindex,
2744 const char *relpath, struct got_object_id *tree_id, const char *entry_name,
2745 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
2746 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
2748 const struct got_error *err = NULL;
2749 struct got_commit_object *commit = NULL;
2750 struct got_tree_object *tree = NULL;
2751 struct got_fileindex_diff_tree_cb diff_cb;
2752 struct diff_cb_arg arg;
2754 err = ref_base_commit(worktree, repo);
2755 if (err) {
2756 if (!(err->code == GOT_ERR_ERRNO &&
2757 (errno == EACCES || errno == EROFS)))
2758 goto done;
2759 err = (*progress_cb)(progress_arg,
2760 GOT_STATUS_BASE_REF_ERR, worktree->root_path);
2761 if (err)
2762 return err;
2765 err = got_object_open_as_commit(&commit, repo,
2766 worktree->base_commit_id);
2767 if (err)
2768 goto done;
2770 err = got_object_open_as_tree(&tree, repo, tree_id);
2771 if (err)
2772 goto done;
2774 if (entry_name &&
2775 got_object_tree_find_entry(tree, entry_name) == NULL) {
2776 err = got_error_path(entry_name, GOT_ERR_NO_TREE_ENTRY);
2777 goto done;
2780 diff_cb.diff_old_new = diff_old_new;
2781 diff_cb.diff_old = diff_old;
2782 diff_cb.diff_new = diff_new;
2783 arg.fileindex = fileindex;
2784 arg.worktree = worktree;
2785 arg.repo = repo;
2786 arg.progress_cb = progress_cb;
2787 arg.progress_arg = progress_arg;
2788 arg.cancel_cb = cancel_cb;
2789 arg.cancel_arg = cancel_arg;
2790 err = got_fileindex_diff_tree(fileindex, tree, relpath,
2791 entry_name, repo, &diff_cb, &arg);
2792 done:
2793 if (tree)
2794 got_object_tree_close(tree);
2795 if (commit)
2796 got_object_commit_close(commit);
2797 return err;
2800 const struct got_error *
2801 got_worktree_checkout_files(struct got_worktree *worktree,
2802 struct got_pathlist_head *paths, struct got_repository *repo,
2803 got_worktree_checkout_cb progress_cb, void *progress_arg,
2804 got_cancel_cb cancel_cb, void *cancel_arg)
2806 const struct got_error *err = NULL, *sync_err, *unlockerr;
2807 struct got_commit_object *commit = NULL;
2808 struct got_tree_object *tree = NULL;
2809 struct got_fileindex *fileindex = NULL;
2810 char *fileindex_path = NULL;
2811 struct got_pathlist_entry *pe;
2812 struct tree_path_data {
2813 STAILQ_ENTRY(tree_path_data) entry;
2814 struct got_object_id *tree_id;
2815 int entry_type;
2816 char *relpath;
2817 char *entry_name;
2818 } *tpd = NULL;
2819 STAILQ_HEAD(tree_paths, tree_path_data) tree_paths;
2821 STAILQ_INIT(&tree_paths);
2823 err = lock_worktree(worktree, LOCK_EX);
2824 if (err)
2825 return err;
2827 err = got_object_open_as_commit(&commit, repo,
2828 worktree->base_commit_id);
2829 if (err)
2830 goto done;
2832 /* Map all specified paths to in-repository trees. */
2833 TAILQ_FOREACH(pe, paths, entry) {
2834 tpd = malloc(sizeof(*tpd));
2835 if (tpd == NULL) {
2836 err = got_error_from_errno("malloc");
2837 goto done;
2840 err = find_tree_entry_for_checkout(&tpd->entry_type,
2841 &tpd->relpath, &tpd->tree_id, pe->path, commit,
2842 worktree, repo);
2843 if (err) {
2844 free(tpd);
2845 goto done;
2848 if (tpd->entry_type == GOT_OBJ_TYPE_BLOB) {
2849 err = got_path_basename(&tpd->entry_name, pe->path);
2850 if (err) {
2851 free(tpd->relpath);
2852 free(tpd->tree_id);
2853 free(tpd);
2854 goto done;
2856 } else
2857 tpd->entry_name = NULL;
2859 STAILQ_INSERT_TAIL(&tree_paths, tpd, entry);
2863 * Read the file index.
2864 * Checking out files is supposed to be an idempotent operation.
2865 * If the on-disk file index is incomplete we will try to complete it.
2867 err = open_fileindex(&fileindex, &fileindex_path, worktree,
2868 got_repo_get_object_format(repo));
2869 if (err)
2870 goto done;
2872 tpd = STAILQ_FIRST(&tree_paths);
2873 TAILQ_FOREACH(pe, paths, entry) {
2874 struct bump_base_commit_id_arg bbc_arg;
2876 err = checkout_files(worktree, fileindex, tpd->relpath,
2877 tpd->tree_id, tpd->entry_name, repo,
2878 progress_cb, progress_arg, cancel_cb, cancel_arg);
2879 if (err)
2880 break;
2882 bbc_arg.base_commit_id = worktree->base_commit_id;
2883 bbc_arg.entry_name = tpd->entry_name;
2884 bbc_arg.path = pe->path;
2885 bbc_arg.path_len = pe->path_len;
2886 bbc_arg.progress_cb = progress_cb;
2887 bbc_arg.progress_arg = progress_arg;
2888 err = got_fileindex_for_each_entry_safe(fileindex,
2889 bump_base_commit_id, &bbc_arg);
2890 if (err)
2891 break;
2893 tpd = STAILQ_NEXT(tpd, entry);
2895 sync_err = sync_fileindex(fileindex, fileindex_path);
2896 if (sync_err && err == NULL)
2897 err = sync_err;
2898 done:
2899 free(fileindex_path);
2900 if (tree)
2901 got_object_tree_close(tree);
2902 if (commit)
2903 got_object_commit_close(commit);
2904 if (fileindex)
2905 got_fileindex_free(fileindex);
2906 while (!STAILQ_EMPTY(&tree_paths)) {
2907 tpd = STAILQ_FIRST(&tree_paths);
2908 STAILQ_REMOVE_HEAD(&tree_paths, entry);
2909 free(tpd->relpath);
2910 free(tpd->tree_id);
2911 free(tpd);
2913 unlockerr = lock_worktree(worktree, LOCK_SH);
2914 if (unlockerr && err == NULL)
2915 err = unlockerr;
2916 return err;
2919 static const struct got_error *
2920 add_file(struct got_worktree *worktree, struct got_fileindex *fileindex,
2921 struct got_fileindex_entry *ie, const char *ondisk_path,
2922 const char *path2, struct got_blob_object *blob2, mode_t mode2,
2923 int restoring_missing_file, int reverting_versioned_file,
2924 int path_is_unversioned, int allow_bad_symlinks,
2925 struct got_repository *repo,
2926 got_worktree_checkout_cb progress_cb, void *progress_arg)
2928 const struct got_error *err = NULL;
2929 int is_bad_symlink = 0;
2931 if (S_ISLNK(mode2)) {
2932 err = install_symlink(&is_bad_symlink,
2933 worktree, ondisk_path, path2, blob2,
2934 restoring_missing_file,
2935 reverting_versioned_file,
2936 path_is_unversioned, allow_bad_symlinks,
2937 repo, progress_cb, progress_arg);
2938 } else {
2939 err = install_blob(worktree, ondisk_path, path2,
2940 mode2, GOT_DEFAULT_FILE_MODE, blob2,
2941 restoring_missing_file, reverting_versioned_file, 0,
2942 path_is_unversioned, NULL, repo,
2943 progress_cb, progress_arg);
2945 if (err)
2946 return err;
2947 if (ie == NULL) {
2948 /* Adding an unversioned file. */
2949 err = got_fileindex_entry_alloc(&ie, path2);
2950 if (err)
2951 return err;
2952 err = got_fileindex_entry_update(ie,
2953 worktree->root_fd, path2, NULL, NULL, 1);
2954 if (err) {
2955 got_fileindex_entry_free(ie);
2956 return err;
2958 err = got_fileindex_entry_add(fileindex, ie);
2959 if (err) {
2960 got_fileindex_entry_free(ie);
2961 return err;
2963 } else {
2964 /* Re-adding a locally deleted file. */
2965 err = got_fileindex_entry_update(ie,
2966 worktree->root_fd, path2, &ie->blob,
2967 worktree->base_commit_id, 0);
2968 if (err)
2969 return err;
2972 if (is_bad_symlink) {
2973 got_fileindex_entry_filetype_set(ie,
2974 GOT_FILEIDX_MODE_BAD_SYMLINK);
2977 return NULL;
2980 struct merge_file_cb_arg {
2981 struct got_worktree *worktree;
2982 struct got_fileindex *fileindex;
2983 got_worktree_checkout_cb progress_cb;
2984 void *progress_arg;
2985 got_cancel_cb cancel_cb;
2986 void *cancel_arg;
2987 const char *label_orig;
2988 struct got_object_id *commit_id2;
2989 int allow_bad_symlinks;
2992 static const struct got_error *
2993 merge_file_cb(void *arg, struct got_blob_object *blob1,
2994 struct got_blob_object *blob2, FILE *f1, FILE *f2,
2995 struct got_object_id *id1, struct got_object_id *id2,
2996 const char *path1, const char *path2,
2997 mode_t mode1, mode_t mode2, struct got_repository *repo)
2999 static const struct got_error *err = NULL;
3000 struct merge_file_cb_arg *a = arg;
3001 struct got_fileindex_entry *ie;
3002 char *ondisk_path = NULL;
3003 struct stat sb;
3004 unsigned char status;
3005 int local_changes_subsumed;
3006 FILE *f_orig = NULL, *f_deriv = NULL, *f_deriv2 = NULL;
3007 char *id_str = NULL, *label_deriv2 = NULL;
3008 struct got_object_id *id = NULL;
3010 if (blob1 && blob2) {
3011 ie = got_fileindex_entry_get(a->fileindex, path2,
3012 strlen(path2));
3013 if (ie == NULL)
3014 return (*a->progress_cb)(a->progress_arg,
3015 GOT_STATUS_MISSING, path2);
3017 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
3018 path2) == -1)
3019 return got_error_from_errno("asprintf");
3021 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
3022 repo);
3023 if (err)
3024 goto done;
3026 if (status == GOT_STATUS_DELETE) {
3027 err = (*a->progress_cb)(a->progress_arg,
3028 GOT_STATUS_MERGE, path2);
3029 goto done;
3031 if (status != GOT_STATUS_NO_CHANGE &&
3032 status != GOT_STATUS_MODIFY &&
3033 status != GOT_STATUS_CONFLICT &&
3034 status != GOT_STATUS_ADD) {
3035 err = (*a->progress_cb)(a->progress_arg, status, path2);
3036 goto done;
3039 if (S_ISLNK(mode1) && S_ISLNK(mode2)) {
3040 char *link_target2;
3041 err = got_object_blob_read_to_str(&link_target2, blob2);
3042 if (err)
3043 goto done;
3044 err = merge_symlink(a->worktree, blob1, ondisk_path,
3045 path2, a->label_orig, link_target2, a->commit_id2,
3046 repo, a->progress_cb, a->progress_arg);
3047 free(link_target2);
3048 } else {
3049 int fd;
3051 f_orig = got_opentemp();
3052 if (f_orig == NULL) {
3053 err = got_error_from_errno("got_opentemp");
3054 goto done;
3056 err = got_object_blob_dump_to_file(NULL, NULL, NULL,
3057 f_orig, blob1);
3058 if (err)
3059 goto done;
3061 f_deriv2 = got_opentemp();
3062 if (f_deriv2 == NULL)
3063 goto done;
3064 err = got_object_blob_dump_to_file(NULL, NULL, NULL,
3065 f_deriv2, blob2);
3066 if (err)
3067 goto done;
3069 fd = open(ondisk_path,
3070 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
3071 if (fd == -1) {
3072 err = got_error_from_errno2("open",
3073 ondisk_path);
3074 goto done;
3076 f_deriv = fdopen(fd, "r");
3077 if (f_deriv == NULL) {
3078 err = got_error_from_errno2("fdopen",
3079 ondisk_path);
3080 close(fd);
3081 goto done;
3083 err = got_object_id_str(&id_str, a->commit_id2);
3084 if (err)
3085 goto done;
3086 if (asprintf(&label_deriv2, "%s: commit %s",
3087 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
3088 err = got_error_from_errno("asprintf");
3089 goto done;
3091 err = merge_file(&local_changes_subsumed, a->worktree,
3092 f_orig, f_deriv, f_deriv2, ondisk_path, path2,
3093 mode2, a->label_orig, NULL, label_deriv2,
3094 GOT_DIFF_ALGORITHM_PATIENCE, repo,
3095 a->progress_cb, a->progress_arg);
3097 } else if (blob1) {
3098 ie = got_fileindex_entry_get(a->fileindex, path1,
3099 strlen(path1));
3100 if (ie == NULL)
3101 return (*a->progress_cb)(a->progress_arg,
3102 GOT_STATUS_MISSING, path1);
3104 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
3105 path1) == -1)
3106 return got_error_from_errno("asprintf");
3108 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
3109 repo);
3110 if (err)
3111 goto done;
3113 switch (status) {
3114 case GOT_STATUS_NO_CHANGE:
3115 err = (*a->progress_cb)(a->progress_arg,
3116 GOT_STATUS_DELETE, path1);
3117 if (err)
3118 goto done;
3119 err = remove_ondisk_file(a->worktree->root_path, path1);
3120 if (err)
3121 goto done;
3122 if (ie)
3123 got_fileindex_entry_mark_deleted_from_disk(ie);
3124 break;
3125 case GOT_STATUS_DELETE:
3126 case GOT_STATUS_MISSING:
3127 err = (*a->progress_cb)(a->progress_arg,
3128 GOT_STATUS_DELETE, path1);
3129 if (err)
3130 goto done;
3131 if (ie)
3132 got_fileindex_entry_mark_deleted_from_disk(ie);
3133 break;
3134 case GOT_STATUS_MODIFY: {
3135 FILE *blob1_f;
3136 off_t blob1_size;
3137 int obj_type;
3139 * Delete the file only if its content already
3140 * exists in the repository.
3142 err = got_object_blob_file_create(&id, &blob1_f,
3143 &blob1_size, path1, repo);
3144 if (err)
3145 goto done;
3146 if (fclose(blob1_f) == EOF) {
3147 err = got_error_from_errno("fclose");
3148 goto done;
3151 /* Implied existence check. */
3152 err = got_object_get_type(&obj_type, repo, id);
3153 if (err) {
3154 if (err->code != GOT_ERR_NO_OBJ)
3155 goto done;
3156 err = (*a->progress_cb)(a->progress_arg,
3157 GOT_STATUS_CANNOT_DELETE, path1);
3158 goto done;
3159 } else if (obj_type != GOT_OBJ_TYPE_BLOB) {
3160 err = (*a->progress_cb)(a->progress_arg,
3161 GOT_STATUS_CANNOT_DELETE, path1);
3162 goto done;
3164 err = (*a->progress_cb)(a->progress_arg,
3165 GOT_STATUS_DELETE, path1);
3166 if (err)
3167 goto done;
3168 err = remove_ondisk_file(a->worktree->root_path,
3169 path1);
3170 if (err)
3171 goto done;
3172 if (ie)
3173 got_fileindex_entry_mark_deleted_from_disk(ie);
3174 break;
3176 case GOT_STATUS_ADD: {
3177 FILE *blob1_f;
3178 off_t blob1_size;
3180 * Delete the file only if its content already
3181 * exists in the repository.
3183 err = got_object_blob_file_create(&id, &blob1_f,
3184 &blob1_size, path1, repo);
3185 if (err)
3186 goto done;
3187 if (fclose(blob1_f) == EOF) {
3188 err = got_error_from_errno("fclose");
3189 goto done;
3191 if (got_object_id_cmp(id, id1) == 0) {
3192 err = (*a->progress_cb)(a->progress_arg,
3193 GOT_STATUS_DELETE, path1);
3194 if (err)
3195 goto done;
3196 err = remove_ondisk_file(a->worktree->root_path,
3197 path1);
3198 if (err)
3199 goto done;
3200 if (ie)
3201 got_fileindex_entry_remove(a->fileindex,
3202 ie);
3203 } else {
3204 err = (*a->progress_cb)(a->progress_arg,
3205 GOT_STATUS_CANNOT_DELETE, path1);
3207 if (err)
3208 goto done;
3209 break;
3211 case GOT_STATUS_CONFLICT:
3212 err = (*a->progress_cb)(a->progress_arg,
3213 GOT_STATUS_CANNOT_DELETE, path1);
3214 if (err)
3215 goto done;
3216 break;
3217 case GOT_STATUS_OBSTRUCTED:
3218 err = (*a->progress_cb)(a->progress_arg, status, path1);
3219 if (err)
3220 goto done;
3221 break;
3222 default:
3223 break;
3225 } else if (blob2) {
3226 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
3227 path2) == -1)
3228 return got_error_from_errno("asprintf");
3229 ie = got_fileindex_entry_get(a->fileindex, path2,
3230 strlen(path2));
3231 if (ie) {
3232 err = get_file_status(&status, &sb, ie, ondisk_path,
3233 -1, NULL, repo);
3234 if (err)
3235 goto done;
3236 if (status != GOT_STATUS_NO_CHANGE &&
3237 status != GOT_STATUS_MODIFY &&
3238 status != GOT_STATUS_CONFLICT &&
3239 status != GOT_STATUS_ADD &&
3240 status != GOT_STATUS_DELETE) {
3241 err = (*a->progress_cb)(a->progress_arg,
3242 status, path2);
3243 goto done;
3245 if (S_ISLNK(mode2) && S_ISLNK(sb.st_mode)) {
3246 char *link_target2;
3247 err = got_object_blob_read_to_str(&link_target2,
3248 blob2);
3249 if (err)
3250 goto done;
3251 err = merge_symlink(a->worktree, NULL,
3252 ondisk_path, path2, a->label_orig,
3253 link_target2, a->commit_id2, repo,
3254 a->progress_cb, a->progress_arg);
3255 free(link_target2);
3256 } else if (S_ISREG(sb.st_mode)) {
3257 err = merge_blob(&local_changes_subsumed,
3258 a->worktree, NULL, ondisk_path, path2,
3259 sb.st_mode, a->label_orig, blob2,
3260 a->commit_id2, repo, a->progress_cb,
3261 a->progress_arg);
3262 } else if (status != GOT_STATUS_DELETE) {
3263 err = got_error_path(ondisk_path,
3264 GOT_ERR_FILE_OBSTRUCTED);
3266 if (err)
3267 goto done;
3268 if (status == GOT_STATUS_DELETE) {
3269 /* Re-add file with content from new blob. */
3270 err = add_file(a->worktree, a->fileindex, ie,
3271 ondisk_path, path2, blob2, mode2,
3272 0, 0, 0, a->allow_bad_symlinks,
3273 repo, a->progress_cb, a->progress_arg);
3274 if (err)
3275 goto done;
3277 } else {
3278 err = add_file(a->worktree, a->fileindex, NULL,
3279 ondisk_path, path2, blob2, mode2,
3280 0, 0, 1, a->allow_bad_symlinks,
3281 repo, a->progress_cb, a->progress_arg);
3282 if (err)
3283 goto done;
3286 done:
3287 if (f_orig && fclose(f_orig) == EOF && err == NULL)
3288 err = got_error_from_errno("fclose");
3289 if (f_deriv && fclose(f_deriv) == EOF && err == NULL)
3290 err = got_error_from_errno("fclose");
3291 if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL)
3292 err = got_error_from_errno("fclose");
3293 free(id_str);
3294 free(id);
3295 free(label_deriv2);
3296 free(ondisk_path);
3297 return err;
3300 struct check_mixed_commits_args {
3301 struct got_worktree *worktree;
3302 got_cancel_cb cancel_cb;
3303 void *cancel_arg;
3306 static const struct got_error *
3307 check_mixed_commits(void *arg, struct got_fileindex_entry *ie)
3309 const struct got_error *err = NULL;
3310 struct check_mixed_commits_args *a = arg;
3312 if (a->cancel_cb) {
3313 err = a->cancel_cb(a->cancel_arg);
3314 if (err)
3315 return err;
3318 /* Reject merges into a work tree with mixed base commits. */
3319 if (got_fileindex_entry_has_commit(ie) &&
3320 got_object_id_cmp(&ie->commit, a->worktree->base_commit_id) != 0)
3321 return got_error(GOT_ERR_MIXED_COMMITS);
3323 return NULL;
3326 const struct got_error *
3327 got_worktree_get_state(char *state, struct got_repository *repo,
3328 struct got_worktree *worktree,
3329 got_cancel_cb cancel_cb, void *cancel_arg)
3331 const struct got_error *err;
3332 struct got_object_id *base_id, *head_id = NULL;
3333 struct got_reference *head_ref;
3334 struct got_fileindex *fileindex = NULL;
3335 char *fileindex_path = NULL;
3336 struct check_mixed_commits_args cma;
3338 if (worktree == NULL)
3339 return got_error(GOT_ERR_NOT_WORKTREE);
3341 err = got_ref_open(&head_ref, repo,
3342 got_worktree_get_head_ref_name(worktree), 0);
3343 if (err)
3344 return err;
3346 err = got_ref_resolve(&head_id, repo, head_ref);
3347 if (err)
3348 goto done;
3350 *state = GOT_WORKTREE_STATE_UNKNOWN;
3351 base_id = got_worktree_get_base_commit_id(worktree);
3353 cma.worktree = worktree;
3354 cma.cancel_cb = cancel_cb;
3355 cma.cancel_arg = cancel_arg;
3357 if (got_object_id_cmp(base_id, head_id) == 0) {
3358 err = open_fileindex(&fileindex, &fileindex_path, worktree,
3359 got_repo_get_object_format(repo));
3360 if (err)
3361 goto done;
3363 err = got_fileindex_for_each_entry_safe(fileindex,
3364 check_mixed_commits, &cma);
3365 if (err == NULL)
3366 *state = GOT_WORKTREE_STATE_UPTODATE;
3367 else if (err->code == GOT_ERR_MIXED_COMMITS) {
3368 *state = GOT_WORKTREE_STATE_OUTOFDATE;
3369 err = NULL;
3371 } else
3372 *state = GOT_WORKTREE_STATE_OUTOFDATE;
3374 done:
3375 free(head_id);
3376 free(fileindex_path);
3377 got_ref_close(head_ref);
3378 if (fileindex != NULL)
3379 got_fileindex_free(fileindex);
3380 return err;
3383 struct check_merge_conflicts_arg {
3384 struct got_worktree *worktree;
3385 struct got_fileindex *fileindex;
3386 struct got_repository *repo;
3389 static const struct got_error *
3390 check_merge_conflicts(void *arg, struct got_blob_object *blob1,
3391 struct got_blob_object *blob2, FILE *f1, FILE *f2,
3392 struct got_object_id *id1, struct got_object_id *id2,
3393 const char *path1, const char *path2,
3394 mode_t mode1, mode_t mode2, struct got_repository *repo)
3396 const struct got_error *err = NULL;
3397 struct check_merge_conflicts_arg *a = arg;
3398 unsigned char status;
3399 struct stat sb;
3400 struct got_fileindex_entry *ie;
3401 const char *path = path2 ? path2 : path1;
3402 struct got_object_id *id = id2 ? id2 : id1;
3403 char *ondisk_path;
3405 if (id == NULL)
3406 return NULL;
3408 ie = got_fileindex_entry_get(a->fileindex, path, strlen(path));
3409 if (ie == NULL)
3410 return NULL;
3412 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path)
3413 == -1)
3414 return got_error_from_errno("asprintf");
3416 /* Reject merges into a work tree with conflicted files. */
3417 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
3418 free(ondisk_path);
3419 if (err)
3420 return err;
3421 if (status == GOT_STATUS_CONFLICT)
3422 return got_error(GOT_ERR_CONFLICTS);
3424 return NULL;
3427 static const struct got_error *
3428 merge_files(struct got_worktree *worktree, struct got_fileindex *fileindex,
3429 const char *fileindex_path, struct got_object_id *commit_id1,
3430 struct got_object_id *commit_id2, struct got_repository *repo,
3431 got_worktree_checkout_cb progress_cb, void *progress_arg,
3432 got_cancel_cb cancel_cb, void *cancel_arg)
3434 const struct got_error *err = NULL, *sync_err;
3435 struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
3436 struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3437 struct got_commit_object *commit1 = NULL, *commit2 = NULL;
3438 struct check_merge_conflicts_arg cmc_arg;
3439 struct merge_file_cb_arg arg;
3440 char *label_orig = NULL;
3441 FILE *f1 = NULL, *f2 = NULL;
3442 int fd1 = -1, fd2 = -1;
3444 if (commit_id1) {
3445 err = got_object_open_as_commit(&commit1, repo, commit_id1);
3446 if (err)
3447 goto done;
3448 err = got_object_id_by_path(&tree_id1, repo, commit1,
3449 worktree->path_prefix);
3450 if (err && err->code != GOT_ERR_NO_TREE_ENTRY)
3451 goto done;
3453 if (tree_id1) {
3454 char *id_str;
3456 err = got_object_open_as_tree(&tree1, repo, tree_id1);
3457 if (err)
3458 goto done;
3460 err = got_object_id_str(&id_str, commit_id1);
3461 if (err)
3462 goto done;
3464 if (asprintf(&label_orig, "%s: commit %s",
3465 GOT_MERGE_LABEL_BASE, id_str) == -1) {
3466 err = got_error_from_errno("asprintf");
3467 free(id_str);
3468 goto done;
3470 free(id_str);
3472 f1 = got_opentemp();
3473 if (f1 == NULL) {
3474 err = got_error_from_errno("got_opentemp");
3475 goto done;
3479 err = got_object_open_as_commit(&commit2, repo, commit_id2);
3480 if (err)
3481 goto done;
3483 err = got_object_id_by_path(&tree_id2, repo, commit2,
3484 worktree->path_prefix);
3485 if (err)
3486 goto done;
3488 err = got_object_open_as_tree(&tree2, repo, tree_id2);
3489 if (err)
3490 goto done;
3492 f2 = got_opentemp();
3493 if (f2 == NULL) {
3494 err = got_error_from_errno("got_opentemp");
3495 goto done;
3498 fd1 = got_opentempfd();
3499 if (fd1 == -1) {
3500 err = got_error_from_errno("got_opentempfd");
3501 goto done;
3504 fd2 = got_opentempfd();
3505 if (fd2 == -1) {
3506 err = got_error_from_errno("got_opentempfd");
3507 goto done;
3510 cmc_arg.worktree = worktree;
3511 cmc_arg.fileindex = fileindex;
3512 cmc_arg.repo = repo;
3513 err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo,
3514 check_merge_conflicts, &cmc_arg, 0);
3515 if (err)
3516 goto done;
3518 arg.worktree = worktree;
3519 arg.fileindex = fileindex;
3520 arg.progress_cb = progress_cb;
3521 arg.progress_arg = progress_arg;
3522 arg.cancel_cb = cancel_cb;
3523 arg.cancel_arg = cancel_arg;
3524 arg.label_orig = label_orig;
3525 arg.commit_id2 = commit_id2;
3526 arg.allow_bad_symlinks = 1; /* preserve bad symlinks across merges */
3527 err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo,
3528 merge_file_cb, &arg, 1);
3529 sync_err = sync_fileindex(fileindex, fileindex_path);
3530 if (sync_err && err == NULL)
3531 err = sync_err;
3532 done:
3533 if (commit1)
3534 got_object_commit_close(commit1);
3535 if (commit2)
3536 got_object_commit_close(commit2);
3537 if (tree1)
3538 got_object_tree_close(tree1);
3539 if (tree2)
3540 got_object_tree_close(tree2);
3541 if (f1 && fclose(f1) == EOF && err == NULL)
3542 err = got_error_from_errno("fclose");
3543 if (f2 && fclose(f2) == EOF && err == NULL)
3544 err = got_error_from_errno("fclose");
3545 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3546 err = got_error_from_errno("close");
3547 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3548 err = got_error_from_errno("close");
3549 free(label_orig);
3550 return err;
3553 const struct got_error *
3554 got_worktree_merge_files(struct got_worktree *worktree,
3555 struct got_object_id *commit_id1, struct got_object_id *commit_id2,
3556 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
3557 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
3559 const struct got_error *err, *unlockerr;
3560 char *fileindex_path = NULL;
3561 struct got_fileindex *fileindex = NULL;
3562 struct check_mixed_commits_args cma;
3564 err = lock_worktree(worktree, LOCK_EX);
3565 if (err)
3566 return err;
3568 err = open_fileindex(&fileindex, &fileindex_path, worktree,
3569 got_repo_get_object_format(repo));
3570 if (err)
3571 goto done;
3573 cma.worktree = worktree;
3574 cma.cancel_cb = cancel_cb;
3575 cma.cancel_arg = cancel_arg;
3577 err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits,
3578 &cma);
3579 if (err)
3580 goto done;
3582 err = merge_files(worktree, fileindex, fileindex_path, commit_id1,
3583 commit_id2, repo, progress_cb, progress_arg,
3584 cancel_cb, cancel_arg);
3585 done:
3586 if (fileindex)
3587 got_fileindex_free(fileindex);
3588 free(fileindex_path);
3589 unlockerr = lock_worktree(worktree, LOCK_SH);
3590 if (unlockerr && err == NULL)
3591 err = unlockerr;
3592 return err;
3595 struct diff_dir_cb_arg {
3596 struct got_fileindex *fileindex;
3597 struct got_worktree *worktree;
3598 const char *status_path;
3599 size_t status_path_len;
3600 struct got_repository *repo;
3601 got_worktree_status_cb status_cb;
3602 void *status_arg;
3603 got_cancel_cb cancel_cb;
3604 void *cancel_arg;
3605 /* A pathlist containing per-directory pathlists of ignore patterns. */
3606 struct got_pathlist_head *ignores;
3607 int report_unchanged;
3608 int no_ignores;
3611 static const struct got_error *
3612 report_file_status(struct got_fileindex_entry *ie, const char *abspath,
3613 int dirfd, const char *de_name,
3614 got_worktree_status_cb status_cb, void *status_arg,
3615 struct got_repository *repo, int report_unchanged)
3617 const struct got_error *err = NULL;
3618 unsigned char status = GOT_STATUS_NO_CHANGE;
3619 unsigned char staged_status;
3620 struct stat sb;
3621 struct got_object_id blob_id, commit_id, staged_blob_id;
3622 struct got_object_id *blob_idp = NULL, *commit_idp = NULL;
3623 struct got_object_id *staged_blob_idp = NULL;
3625 staged_status = get_staged_status(ie);
3626 err = get_file_status(&status, &sb, ie, abspath, dirfd, de_name, repo);
3627 if (err)
3628 return err;
3630 if (status == GOT_STATUS_NO_CHANGE &&
3631 staged_status == GOT_STATUS_NO_CHANGE && !report_unchanged)
3632 return NULL;
3634 if (got_fileindex_entry_has_blob(ie))
3635 blob_idp = got_fileindex_entry_get_blob_id(&blob_id, ie);
3636 if (got_fileindex_entry_has_commit(ie))
3637 commit_idp = got_fileindex_entry_get_commit_id(&commit_id, ie);
3638 if (staged_status == GOT_STATUS_ADD ||
3639 staged_status == GOT_STATUS_MODIFY) {
3640 staged_blob_idp = got_fileindex_entry_get_staged_blob_id(
3641 &staged_blob_id, ie);
3644 return (*status_cb)(status_arg, status, staged_status,
3645 ie->path, blob_idp, staged_blob_idp, commit_idp, dirfd, de_name);
3648 static const struct got_error *
3649 status_old_new(void *arg, struct got_fileindex_entry *ie,
3650 struct dirent *de, const char *parent_path, int dirfd)
3652 const struct got_error *err = NULL;
3653 struct diff_dir_cb_arg *a = arg;
3654 char *abspath;
3656 if (a->cancel_cb) {
3657 err = a->cancel_cb(a->cancel_arg);
3658 if (err)
3659 return err;
3662 if (got_path_cmp(parent_path, a->status_path,
3663 strlen(parent_path), a->status_path_len) != 0 &&
3664 !got_path_is_child(parent_path, a->status_path, a->status_path_len))
3665 return NULL;
3667 if (parent_path[0]) {
3668 if (asprintf(&abspath, "%s/%s/%s", a->worktree->root_path,
3669 parent_path, de->d_name) == -1)
3670 return got_error_from_errno("asprintf");
3671 } else {
3672 if (asprintf(&abspath, "%s/%s", a->worktree->root_path,
3673 de->d_name) == -1)
3674 return got_error_from_errno("asprintf");
3677 err = report_file_status(ie, abspath, dirfd, de->d_name,
3678 a->status_cb, a->status_arg, a->repo, a->report_unchanged);
3679 free(abspath);
3680 return err;
3683 static const struct got_error *
3684 status_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path)
3686 const struct got_error *err;
3687 struct diff_dir_cb_arg *a = arg;
3688 struct got_object_id blob_id, commit_id;
3689 unsigned char status;
3691 if (a->cancel_cb) {
3692 err = a->cancel_cb(a->cancel_arg);
3693 if (err)
3694 return err;
3697 if (!got_path_is_child(ie->path, a->status_path, a->status_path_len))
3698 return NULL;
3700 got_fileindex_entry_get_blob_id(&blob_id, ie);
3701 got_fileindex_entry_get_commit_id(&commit_id, ie);
3702 if (got_fileindex_entry_has_file_on_disk(ie))
3703 status = GOT_STATUS_MISSING;
3704 else
3705 status = GOT_STATUS_DELETE;
3706 return (*a->status_cb)(a->status_arg, status, get_staged_status(ie),
3707 ie->path, &blob_id, NULL, &commit_id, -1, NULL);
3710 static void
3711 free_ignores(struct got_pathlist_head *ignores)
3713 struct got_pathlist_entry *pe;
3715 TAILQ_FOREACH(pe, ignores, entry) {
3716 struct got_pathlist_head *ignorelist = pe->data;
3718 got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH);
3720 got_pathlist_free(ignores, GOT_PATHLIST_FREE_ALL);
3723 static const struct got_error *
3724 read_ignores(struct got_pathlist_head *ignores, const char *path, FILE *f)
3726 const struct got_error *err = NULL;
3727 struct got_pathlist_entry *pe = NULL;
3728 struct got_pathlist_head *ignorelist;
3729 char *line = NULL, *pattern, *dirpath = NULL;
3730 size_t linesize = 0;
3731 ssize_t linelen;
3733 ignorelist = calloc(1, sizeof(*ignorelist));
3734 if (ignorelist == NULL)
3735 return got_error_from_errno("calloc");
3736 TAILQ_INIT(ignorelist);
3738 while ((linelen = getline(&line, &linesize, f)) != -1) {
3739 if (linelen > 0 && line[linelen - 1] == '\n')
3740 line[linelen - 1] = '\0';
3742 /* Skip blank lines. */
3743 if (line[0] == '\0')
3744 continue;
3746 /* Git's ignores may contain comments. */
3747 if (line[0] == '#')
3748 continue;
3750 /* Git's negated patterns are not (yet?) supported. */
3751 if (line[0] == '!')
3752 continue;
3754 if (asprintf(&pattern, "%s%s%s", path, path[0] ? "/" : "",
3755 line) == -1) {
3756 err = got_error_from_errno("asprintf");
3757 goto done;
3759 err = got_pathlist_insert(NULL, ignorelist, pattern, NULL);
3760 if (err)
3761 goto done;
3763 if (ferror(f)) {
3764 err = got_error_from_errno("getline");
3765 goto done;
3768 dirpath = strdup(path);
3769 if (dirpath == NULL) {
3770 err = got_error_from_errno("strdup");
3771 goto done;
3773 err = got_pathlist_insert(&pe, ignores, dirpath, ignorelist);
3774 done:
3775 free(line);
3776 if (err || pe == NULL) {
3777 free(dirpath);
3778 got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH);
3779 free(ignorelist);
3781 return err;
3784 static int
3785 match_path(const char *pattern, size_t pattern_len, const char *path,
3786 int flags)
3788 char buf[PATH_MAX];
3791 * Trailing slashes signify directories.
3792 * Append a * to make such patterns conform to fnmatch rules.
3794 if (pattern_len > 0 && pattern[pattern_len - 1] == '/') {
3795 if (snprintf(buf, sizeof(buf), "%s*", pattern) >= sizeof(buf))
3796 return FNM_NOMATCH; /* XXX */
3798 return fnmatch(buf, path, flags);
3801 return fnmatch(pattern, path, flags);
3804 static int
3805 match_ignores(struct got_pathlist_head *ignores, const char *path)
3807 struct got_pathlist_entry *pe;
3809 /* Handle patterns which match in all directories. */
3810 TAILQ_FOREACH(pe, ignores, entry) {
3811 struct got_pathlist_head *ignorelist = pe->data;
3812 struct got_pathlist_entry *pi;
3814 TAILQ_FOREACH(pi, ignorelist, entry) {
3815 const char *p;
3817 if (pi->path_len < 3 ||
3818 strncmp(pi->path, "**/", 3) != 0)
3819 continue;
3820 p = path;
3821 while (*p) {
3822 if (match_path(pi->path + 3,
3823 pi->path_len - 3, p,
3824 FNM_PATHNAME | FNM_LEADING_DIR)) {
3825 /* Retry in next directory. */
3826 while (*p && *p != '/')
3827 p++;
3828 while (*p == '/')
3829 p++;
3830 continue;
3832 return 1;
3838 * The ignores pathlist contains ignore lists from children before
3839 * parents, so we can find the most specific ignorelist by walking
3840 * ignores backwards.
3842 pe = TAILQ_LAST(ignores, got_pathlist_head);
3843 while (pe) {
3844 if (got_path_is_child(path, pe->path, pe->path_len)) {
3845 struct got_pathlist_head *ignorelist = pe->data;
3846 struct got_pathlist_entry *pi;
3847 TAILQ_FOREACH(pi, ignorelist, entry) {
3848 int flags = FNM_LEADING_DIR;
3849 if (strstr(pi->path, "/**/") == NULL)
3850 flags |= FNM_PATHNAME;
3851 if (match_path(pi->path, pi->path_len,
3852 path, flags))
3853 continue;
3854 return 1;
3857 pe = TAILQ_PREV(pe, got_pathlist_head, entry);
3860 return 0;
3863 static const struct got_error *
3864 add_ignores(struct got_pathlist_head *ignores, const char *root_path,
3865 const char *path, int dirfd, const char *ignores_filename)
3867 const struct got_error *err = NULL;
3868 char *ignorespath;
3869 int fd = -1;
3870 FILE *ignoresfile = NULL;
3872 if (asprintf(&ignorespath, "%s/%s%s%s", root_path, path,
3873 path[0] ? "/" : "", ignores_filename) == -1)
3874 return got_error_from_errno("asprintf");
3876 if (dirfd != -1) {
3877 fd = openat(dirfd, ignores_filename,
3878 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
3879 if (fd == -1) {
3880 if (errno != ENOENT && errno != EACCES)
3881 err = got_error_from_errno2("openat",
3882 ignorespath);
3883 } else {
3884 ignoresfile = fdopen(fd, "r");
3885 if (ignoresfile == NULL)
3886 err = got_error_from_errno2("fdopen",
3887 ignorespath);
3888 else {
3889 fd = -1;
3890 err = read_ignores(ignores, path, ignoresfile);
3893 } else {
3894 ignoresfile = fopen(ignorespath, "re");
3895 if (ignoresfile == NULL) {
3896 if (errno != ENOENT && errno != EACCES)
3897 err = got_error_from_errno2("fopen",
3898 ignorespath);
3899 } else
3900 err = read_ignores(ignores, path, ignoresfile);
3903 if (ignoresfile && fclose(ignoresfile) == EOF && err == NULL)
3904 err = got_error_from_errno2("fclose", path);
3905 if (fd != -1 && close(fd) == -1 && err == NULL)
3906 err = got_error_from_errno2("close", path);
3907 free(ignorespath);
3908 return err;
3911 static const struct got_error *
3912 status_new(int *ignore, void *arg, struct dirent *de, const char *parent_path,
3913 int dirfd)
3915 const struct got_error *err = NULL;
3916 struct diff_dir_cb_arg *a = arg;
3917 char *path = NULL;
3919 if (ignore != NULL)
3920 *ignore = 0;
3922 if (a->cancel_cb) {
3923 err = a->cancel_cb(a->cancel_arg);
3924 if (err)
3925 return err;
3928 if (parent_path[0]) {
3929 if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1)
3930 return got_error_from_errno("asprintf");
3931 } else {
3932 path = de->d_name;
3935 if (de->d_type == DT_DIR) {
3936 if (!a->no_ignores && ignore != NULL &&
3937 match_ignores(a->ignores, path))
3938 *ignore = 1;
3939 } else if (!match_ignores(a->ignores, path) &&
3940 got_path_is_child(path, a->status_path, a->status_path_len))
3941 err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED,
3942 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3943 if (parent_path[0])
3944 free(path);
3945 return err;
3948 static const struct got_error *
3949 status_traverse(void *arg, const char *path, int dirfd)
3951 const struct got_error *err = NULL;
3952 struct diff_dir_cb_arg *a = arg;
3954 if (a->no_ignores)
3955 return NULL;
3957 err = add_ignores(a->ignores, a->worktree->root_path,
3958 path, dirfd, ".cvsignore");
3959 if (err)
3960 return err;
3962 err = add_ignores(a->ignores, a->worktree->root_path, path,
3963 dirfd, ".gitignore");
3965 return err;
3968 static const struct got_error *
3969 report_single_file_status(const char *path, const char *ondisk_path,
3970 struct got_fileindex *fileindex, got_worktree_status_cb status_cb,
3971 void *status_arg, struct got_repository *repo, int report_unchanged,
3972 struct got_pathlist_head *ignores, int no_ignores)
3974 struct got_fileindex_entry *ie;
3975 struct stat sb;
3977 ie = got_fileindex_entry_get(fileindex, path, strlen(path));
3978 if (ie)
3979 return report_file_status(ie, ondisk_path, -1, NULL,
3980 status_cb, status_arg, repo, report_unchanged);
3982 if (lstat(ondisk_path, &sb) == -1) {
3983 if (errno != ENOENT)
3984 return got_error_from_errno2("lstat", ondisk_path);
3985 return (*status_cb)(status_arg, GOT_STATUS_NONEXISTENT,
3986 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3989 if (!no_ignores && match_ignores(ignores, path))
3990 return NULL;
3992 if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode))
3993 return (*status_cb)(status_arg, GOT_STATUS_UNVERSIONED,
3994 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3996 return NULL;
3999 static const struct got_error *
4000 add_ignores_from_parent_paths(struct got_pathlist_head *ignores,
4001 const char *root_path, const char *path)
4003 const struct got_error *err;
4004 char *parent_path, *next_parent_path = NULL;
4006 err = add_ignores(ignores, root_path, "", -1,
4007 ".cvsignore");
4008 if (err)
4009 return err;
4011 err = add_ignores(ignores, root_path, "", -1,
4012 ".gitignore");
4013 if (err)
4014 return err;
4016 err = got_path_dirname(&parent_path, path);
4017 if (err) {
4018 if (err->code == GOT_ERR_BAD_PATH)
4019 return NULL; /* cannot traverse parent */
4020 return err;
4022 for (;;) {
4023 err = add_ignores(ignores, root_path, parent_path, -1,
4024 ".cvsignore");
4025 if (err)
4026 break;
4027 err = add_ignores(ignores, root_path, parent_path, -1,
4028 ".gitignore");
4029 if (err)
4030 break;
4031 err = got_path_dirname(&next_parent_path, parent_path);
4032 if (err) {
4033 if (err->code == GOT_ERR_BAD_PATH)
4034 err = NULL; /* traversed everything */
4035 break;
4037 if (got_path_is_root_dir(parent_path))
4038 break;
4039 free(parent_path);
4040 parent_path = next_parent_path;
4041 next_parent_path = NULL;
4044 free(parent_path);
4045 free(next_parent_path);
4046 return err;
4049 struct find_missing_children_args {
4050 const char *parent_path;
4051 size_t parent_len;
4052 struct got_pathlist_head *children;
4053 got_cancel_cb cancel_cb;
4054 void *cancel_arg;
4057 static const struct got_error *
4058 find_missing_children(void *arg, struct got_fileindex_entry *ie)
4060 const struct got_error *err = NULL;
4061 struct find_missing_children_args *a = arg;
4063 if (a->cancel_cb) {
4064 err = a->cancel_cb(a->cancel_arg);
4065 if (err)
4066 return err;
4069 if (got_path_is_child(ie->path, a->parent_path, a->parent_len))
4070 err = got_pathlist_insert(NULL, a->children, ie->path, NULL);
4072 return err;
4075 static const struct got_error *
4076 report_children(struct got_pathlist_head *children,
4077 struct got_worktree *worktree, struct got_fileindex *fileindex,
4078 struct got_repository *repo, int is_root_dir, int report_unchanged,
4079 struct got_pathlist_head *ignores, int no_ignores,
4080 got_worktree_status_cb status_cb, void *status_arg,
4081 got_cancel_cb cancel_cb, void *cancel_arg)
4083 const struct got_error *err = NULL;
4084 struct got_pathlist_entry *pe;
4085 char *ondisk_path = NULL;
4087 TAILQ_FOREACH(pe, children, entry) {
4088 if (cancel_cb) {
4089 err = cancel_cb(cancel_arg);
4090 if (err)
4091 break;
4094 if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path,
4095 !is_root_dir ? "/" : "", pe->path) == -1) {
4096 err = got_error_from_errno("asprintf");
4097 ondisk_path = NULL;
4098 break;
4101 err = report_single_file_status(pe->path, ondisk_path,
4102 fileindex, status_cb, status_arg, repo, report_unchanged,
4103 ignores, no_ignores);
4104 if (err)
4105 break;
4107 free(ondisk_path);
4108 ondisk_path = NULL;
4111 free(ondisk_path);
4112 return err;
4115 static const struct got_error *
4116 worktree_status(struct got_worktree *worktree, const char *path,
4117 struct got_fileindex *fileindex, struct got_repository *repo,
4118 got_worktree_status_cb status_cb, void *status_arg,
4119 got_cancel_cb cancel_cb, void *cancel_arg, int no_ignores,
4120 int report_unchanged)
4122 const struct got_error *err = NULL;
4123 int fd = -1;
4124 struct got_fileindex_diff_dir_cb fdiff_cb;
4125 struct diff_dir_cb_arg arg;
4126 char *ondisk_path = NULL;
4127 struct got_pathlist_head ignores, missing_children;
4128 struct got_fileindex_entry *ie;
4130 TAILQ_INIT(&ignores);
4131 TAILQ_INIT(&missing_children);
4133 if (asprintf(&ondisk_path, "%s%s%s",
4134 worktree->root_path, path[0] ? "/" : "", path) == -1)
4135 return got_error_from_errno("asprintf");
4137 ie = got_fileindex_entry_get(fileindex, path, strlen(path));
4138 if (ie) {
4139 err = report_single_file_status(path, ondisk_path,
4140 fileindex, status_cb, status_arg, repo,
4141 report_unchanged, &ignores, no_ignores);
4142 goto done;
4143 } else {
4144 struct find_missing_children_args fmca;
4145 fmca.parent_path = path;
4146 fmca.parent_len = strlen(path);
4147 fmca.children = &missing_children;
4148 fmca.cancel_cb = cancel_cb;
4149 fmca.cancel_arg = cancel_arg;
4150 err = got_fileindex_for_each_entry_safe(fileindex,
4151 find_missing_children, &fmca);
4152 if (err)
4153 goto done;
4156 fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
4157 if (fd == -1) {
4158 if (errno != ENOTDIR && errno != ENOENT && errno != EACCES &&
4159 !got_err_open_nofollow_on_symlink())
4160 err = got_error_from_errno2("open", ondisk_path);
4161 else {
4162 if (!no_ignores) {
4163 err = add_ignores_from_parent_paths(&ignores,
4164 worktree->root_path, ondisk_path);
4165 if (err)
4166 goto done;
4168 if (TAILQ_EMPTY(&missing_children)) {
4169 err = report_single_file_status(path,
4170 ondisk_path, fileindex,
4171 status_cb, status_arg, repo,
4172 report_unchanged, &ignores, no_ignores);
4173 if (err)
4174 goto done;
4175 } else {
4176 err = report_children(&missing_children,
4177 worktree, fileindex, repo,
4178 (path[0] == '\0'), report_unchanged,
4179 &ignores, no_ignores,
4180 status_cb, status_arg,
4181 cancel_cb, cancel_arg);
4182 if (err)
4183 goto done;
4186 } else {
4187 fdiff_cb.diff_old_new = status_old_new;
4188 fdiff_cb.diff_old = status_old;
4189 fdiff_cb.diff_new = status_new;
4190 fdiff_cb.diff_traverse = status_traverse;
4191 arg.fileindex = fileindex;
4192 arg.worktree = worktree;
4193 arg.status_path = path;
4194 arg.status_path_len = strlen(path);
4195 arg.repo = repo;
4196 arg.status_cb = status_cb;
4197 arg.status_arg = status_arg;
4198 arg.cancel_cb = cancel_cb;
4199 arg.cancel_arg = cancel_arg;
4200 arg.report_unchanged = report_unchanged;
4201 arg.no_ignores = no_ignores;
4202 if (!no_ignores) {
4203 err = add_ignores_from_parent_paths(&ignores,
4204 worktree->root_path, path);
4205 if (err)
4206 goto done;
4208 arg.ignores = &ignores;
4209 err = got_fileindex_diff_dir(fileindex, fd,
4210 worktree->root_path, path, repo, &fdiff_cb, &arg);
4212 done:
4213 free_ignores(&ignores);
4214 got_pathlist_free(&missing_children, GOT_PATHLIST_FREE_NONE);
4215 if (fd != -1 && close(fd) == -1 && err == NULL)
4216 err = got_error_from_errno("close");
4217 free(ondisk_path);
4218 return err;
4221 const struct got_error *
4222 got_worktree_status(struct got_worktree *worktree,
4223 struct got_pathlist_head *paths, struct got_repository *repo,
4224 int no_ignores, got_worktree_status_cb status_cb, void *status_arg,
4225 got_cancel_cb cancel_cb, void *cancel_arg)
4227 const struct got_error *err = NULL;
4228 char *fileindex_path = NULL;
4229 struct got_fileindex *fileindex = NULL;
4230 struct got_pathlist_entry *pe;
4232 err = open_fileindex(&fileindex, &fileindex_path, worktree,
4233 got_repo_get_object_format(repo));
4234 if (err)
4235 return err;
4237 TAILQ_FOREACH(pe, paths, entry) {
4238 err = worktree_status(worktree, pe->path, fileindex, repo,
4239 status_cb, status_arg, cancel_cb, cancel_arg,
4240 no_ignores, 0);
4241 if (err)
4242 break;
4244 free(fileindex_path);
4245 got_fileindex_free(fileindex);
4246 return err;
4249 const struct got_error *
4250 got_worktree_resolve_path(char **wt_path, struct got_worktree *worktree,
4251 const char *arg)
4253 const struct got_error *err = NULL;
4254 char *resolved = NULL, *cwd = NULL, *path = NULL;
4255 size_t len;
4256 struct stat sb;
4257 char *abspath = NULL;
4258 char canonpath[PATH_MAX];
4260 *wt_path = NULL;
4262 cwd = getcwd(NULL, 0);
4263 if (cwd == NULL)
4264 return got_error_from_errno("getcwd");
4266 if (lstat(arg, &sb) == -1) {
4267 if (errno != ENOENT) {
4268 err = got_error_from_errno2("lstat", arg);
4269 goto done;
4271 sb.st_mode = 0;
4273 if (S_ISLNK(sb.st_mode)) {
4275 * We cannot use realpath(3) with symlinks since we want to
4276 * operate on the symlink itself.
4277 * But we can make the path absolute, assuming it is relative
4278 * to the current working directory, and then canonicalize it.
4280 if (!got_path_is_absolute(arg)) {
4281 if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) {
4282 err = got_error_from_errno("asprintf");
4283 goto done;
4287 err = got_canonpath(abspath ? abspath : arg, canonpath,
4288 sizeof(canonpath));
4289 if (err)
4290 goto done;
4291 resolved = strdup(canonpath);
4292 if (resolved == NULL) {
4293 err = got_error_from_errno("strdup");
4294 goto done;
4296 } else {
4297 resolved = realpath(arg, NULL);
4298 if (resolved == NULL) {
4299 if (errno != ENOENT) {
4300 err = got_error_from_errno2("realpath", arg);
4301 goto done;
4303 if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) {
4304 err = got_error_from_errno("asprintf");
4305 goto done;
4307 err = got_canonpath(abspath, canonpath,
4308 sizeof(canonpath));
4309 if (err)
4310 goto done;
4311 resolved = strdup(canonpath);
4312 if (resolved == NULL) {
4313 err = got_error_from_errno("strdup");
4314 goto done;
4319 if (strncmp(got_worktree_get_root_path(worktree), resolved,
4320 strlen(got_worktree_get_root_path(worktree)))) {
4321 err = got_error_path(resolved, GOT_ERR_BAD_PATH);
4322 goto done;
4325 if (strlen(resolved) > strlen(got_worktree_get_root_path(worktree))) {
4326 err = got_path_skip_common_ancestor(&path,
4327 got_worktree_get_root_path(worktree), resolved);
4328 if (err)
4329 goto done;
4330 } else {
4331 path = strdup("");
4332 if (path == NULL) {
4333 err = got_error_from_errno("strdup");
4334 goto done;
4338 /* XXX status walk can't deal with trailing slash! */
4339 len = strlen(path);
4340 while (len > 0 && path[len - 1] == '/') {
4341 path[len - 1] = '\0';
4342 len--;
4344 done:
4345 free(abspath);
4346 free(resolved);
4347 free(cwd);
4348 if (err == NULL)
4349 *wt_path = path;
4350 else
4351 free(path);
4352 return err;
4355 struct schedule_addition_args {
4356 struct got_worktree *worktree;
4357 struct got_fileindex *fileindex;
4358 got_worktree_checkout_cb progress_cb;
4359 void *progress_arg;
4360 struct got_repository *repo;
4363 static int
4364 add_noop_status(unsigned char status)
4366 return (status == GOT_STATUS_ADD ||
4367 status == GOT_STATUS_MODIFY ||
4368 status == GOT_STATUS_CONFLICT ||
4369 status == GOT_STATUS_MODE_CHANGE ||
4370 status == GOT_STATUS_NO_CHANGE);
4373 static const struct got_error *
4374 schedule_addition(void *arg, unsigned char status, unsigned char staged_status,
4375 const char *relpath, struct got_object_id *blob_id,
4376 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4377 int dirfd, const char *de_name)
4379 struct schedule_addition_args *a = arg;
4380 const struct got_error *err = NULL;
4381 struct got_fileindex_entry *ie;
4382 struct stat sb;
4383 char *ondisk_path;
4385 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
4386 relpath) == -1)
4387 return got_error_from_errno("asprintf");
4389 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
4390 if (ie) {
4391 err = get_file_status(&status, &sb, ie, ondisk_path, dirfd,
4392 de_name, a->repo);
4393 if (err)
4394 goto done;
4395 /* Re-adding an existing entry is a no-op. */
4396 if (staged_status == GOT_STATUS_NO_CHANGE &&
4397 add_noop_status(status))
4398 goto done;
4399 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
4400 if (err)
4401 goto done;
4404 if (status != GOT_STATUS_UNVERSIONED) {
4405 if (status == GOT_STATUS_NONEXISTENT)
4406 err = got_error_set_errno(ENOENT, ondisk_path);
4407 else
4408 err = got_error_path(ondisk_path, GOT_ERR_FILE_STATUS);
4409 goto done;
4412 err = got_fileindex_entry_alloc(&ie, relpath);
4413 if (err)
4414 goto done;
4415 err = got_fileindex_entry_update(ie, a->worktree->root_fd,
4416 relpath, NULL, NULL, 1);
4417 if (err) {
4418 got_fileindex_entry_free(ie);
4419 goto done;
4421 err = got_fileindex_entry_add(a->fileindex, ie);
4422 if (err) {
4423 got_fileindex_entry_free(ie);
4424 goto done;
4426 done:
4427 free(ondisk_path);
4428 if (err)
4429 return err;
4430 if (staged_status == GOT_STATUS_NO_CHANGE && add_noop_status(status))
4431 return NULL;
4432 return (*a->progress_cb)(a->progress_arg, GOT_STATUS_ADD, relpath);
4435 const struct got_error *
4436 got_worktree_schedule_add(struct got_worktree *worktree,
4437 struct got_pathlist_head *paths,
4438 got_worktree_checkout_cb progress_cb, void *progress_arg,
4439 struct got_repository *repo, int no_ignores)
4441 struct got_fileindex *fileindex = NULL;
4442 char *fileindex_path = NULL;
4443 const struct got_error *err = NULL, *sync_err, *unlockerr;
4444 struct got_pathlist_entry *pe;
4445 struct schedule_addition_args saa;
4447 err = lock_worktree(worktree, LOCK_EX);
4448 if (err)
4449 return err;
4451 err = open_fileindex(&fileindex, &fileindex_path, worktree,
4452 got_repo_get_object_format(repo));
4453 if (err)
4454 goto done;
4456 saa.worktree = worktree;
4457 saa.fileindex = fileindex;
4458 saa.progress_cb = progress_cb;
4459 saa.progress_arg = progress_arg;
4460 saa.repo = repo;
4462 TAILQ_FOREACH(pe, paths, entry) {
4463 err = worktree_status(worktree, pe->path, fileindex, repo,
4464 schedule_addition, &saa, NULL, NULL, no_ignores, 0);
4465 if (err)
4466 break;
4468 sync_err = sync_fileindex(fileindex, fileindex_path);
4469 if (sync_err && err == NULL)
4470 err = sync_err;
4471 done:
4472 free(fileindex_path);
4473 if (fileindex)
4474 got_fileindex_free(fileindex);
4475 unlockerr = lock_worktree(worktree, LOCK_SH);
4476 if (unlockerr && err == NULL)
4477 err = unlockerr;
4478 return err;
4481 struct schedule_deletion_args {
4482 struct got_worktree *worktree;
4483 struct got_fileindex *fileindex;
4484 got_worktree_delete_cb progress_cb;
4485 void *progress_arg;
4486 struct got_repository *repo;
4487 int delete_local_mods;
4488 int keep_on_disk;
4489 int ignore_missing_paths;
4490 const char *status_path;
4491 size_t status_path_len;
4492 const char *status_codes;
4495 static const struct got_error *
4496 schedule_for_deletion(void *arg, unsigned char status,
4497 unsigned char staged_status, const char *relpath,
4498 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
4499 struct got_object_id *commit_id, int dirfd, const char *de_name)
4501 struct schedule_deletion_args *a = arg;
4502 const struct got_error *err = NULL;
4503 struct got_fileindex_entry *ie = NULL;
4504 struct stat sb;
4505 char *ondisk_path;
4507 if (status == GOT_STATUS_NONEXISTENT) {
4508 if (a->ignore_missing_paths)
4509 return NULL;
4510 return got_error_set_errno(ENOENT, relpath);
4513 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
4514 if (ie == NULL)
4515 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
4517 staged_status = get_staged_status(ie);
4518 if (staged_status != GOT_STATUS_NO_CHANGE) {
4519 if (staged_status == GOT_STATUS_DELETE)
4520 return NULL;
4521 return got_error_path(relpath, GOT_ERR_FILE_STAGED);
4524 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
4525 relpath) == -1)
4526 return got_error_from_errno("asprintf");
4528 err = get_file_status(&status, &sb, ie, ondisk_path, dirfd, de_name,
4529 a->repo);
4530 if (err)
4531 goto done;
4533 if (a->status_codes) {
4534 size_t ncodes = strlen(a->status_codes);
4535 int i;
4536 for (i = 0; i < ncodes ; i++) {
4537 if (status == a->status_codes[i])
4538 break;
4540 if (i == ncodes) {
4541 /* Do not delete files in non-matching status. */
4542 free(ondisk_path);
4543 return NULL;
4545 if (a->status_codes[i] != GOT_STATUS_MODIFY &&
4546 a->status_codes[i] != GOT_STATUS_MISSING) {
4547 static char msg[64];
4548 snprintf(msg, sizeof(msg),
4549 "invalid status code '%c'", a->status_codes[i]);
4550 err = got_error_msg(GOT_ERR_FILE_STATUS, msg);
4551 goto done;
4555 if (status != GOT_STATUS_NO_CHANGE) {
4556 if (status == GOT_STATUS_DELETE)
4557 goto done;
4558 if (status == GOT_STATUS_MODIFY && !a->delete_local_mods) {
4559 err = got_error_path(relpath, GOT_ERR_FILE_MODIFIED);
4560 goto done;
4562 if (status == GOT_STATUS_MISSING && !a->ignore_missing_paths) {
4563 err = got_error_set_errno(ENOENT, relpath);
4564 goto done;
4566 if (status != GOT_STATUS_MODIFY &&
4567 status != GOT_STATUS_MISSING) {
4568 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
4569 goto done;
4573 if (!a->keep_on_disk && status != GOT_STATUS_MISSING) {
4574 size_t root_len;
4576 if (dirfd != -1) {
4577 if (unlinkat(dirfd, de_name, 0) == -1) {
4578 err = got_error_from_errno2("unlinkat",
4579 ondisk_path);
4580 goto done;
4582 } else if (unlink(ondisk_path) == -1) {
4583 err = got_error_from_errno2("unlink", ondisk_path);
4584 goto done;
4587 root_len = strlen(a->worktree->root_path);
4588 do {
4589 char *parent;
4591 err = got_path_dirname(&parent, ondisk_path);
4592 if (err)
4593 goto done;
4594 free(ondisk_path);
4595 ondisk_path = parent;
4596 if (got_path_cmp(ondisk_path, a->status_path,
4597 strlen(ondisk_path), a->status_path_len) != 0 &&
4598 !got_path_is_child(ondisk_path, a->status_path,
4599 a->status_path_len))
4600 break;
4601 if (rmdir(ondisk_path) == -1) {
4602 if (errno != ENOTEMPTY)
4603 err = got_error_from_errno2("rmdir",
4604 ondisk_path);
4605 break;
4607 } while (got_path_cmp(ondisk_path, a->worktree->root_path,
4608 strlen(ondisk_path), root_len) != 0);
4611 if (got_fileindex_entry_has_blob(ie))
4612 got_fileindex_entry_mark_deleted_from_disk(ie);
4613 else
4614 got_fileindex_entry_remove(a->fileindex, ie);
4615 done:
4616 free(ondisk_path);
4617 if (err)
4618 return err;
4619 if (status == GOT_STATUS_DELETE)
4620 return NULL;
4621 return (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE,
4622 staged_status, relpath);
4625 const struct got_error *
4626 got_worktree_schedule_delete(struct got_worktree *worktree,
4627 struct got_pathlist_head *paths, int delete_local_mods,
4628 const char *status_codes,
4629 got_worktree_delete_cb progress_cb, void *progress_arg,
4630 struct got_repository *repo, int keep_on_disk, int ignore_missing_paths)
4632 struct got_fileindex *fileindex = NULL;
4633 char *fileindex_path = NULL;
4634 const struct got_error *err = NULL, *sync_err, *unlockerr;
4635 struct got_pathlist_entry *pe;
4636 struct schedule_deletion_args sda;
4638 err = lock_worktree(worktree, LOCK_EX);
4639 if (err)
4640 return err;
4642 err = open_fileindex(&fileindex, &fileindex_path, worktree,
4643 got_repo_get_object_format(repo));
4644 if (err)
4645 goto done;
4647 sda.worktree = worktree;
4648 sda.fileindex = fileindex;
4649 sda.progress_cb = progress_cb;
4650 sda.progress_arg = progress_arg;
4651 sda.repo = repo;
4652 sda.delete_local_mods = delete_local_mods;
4653 sda.keep_on_disk = keep_on_disk;
4654 sda.ignore_missing_paths = ignore_missing_paths;
4655 sda.status_codes = status_codes;
4657 TAILQ_FOREACH(pe, paths, entry) {
4658 char *ondisk_status_path;
4660 if (asprintf(&ondisk_status_path, "%s%s%s",
4661 got_worktree_get_root_path(worktree),
4662 pe->path[0] == '\0' ? "" : "/", pe->path) == -1) {
4663 err = got_error_from_errno("asprintf");
4664 goto done;
4666 sda.status_path = ondisk_status_path;
4667 sda.status_path_len = strlen(ondisk_status_path);
4668 err = worktree_status(worktree, pe->path, fileindex, repo,
4669 schedule_for_deletion, &sda, NULL, NULL, 1, 1);
4670 free(ondisk_status_path);
4671 if (err)
4672 break;
4674 sync_err = sync_fileindex(fileindex, fileindex_path);
4675 if (sync_err && err == NULL)
4676 err = sync_err;
4677 done:
4678 free(fileindex_path);
4679 if (fileindex)
4680 got_fileindex_free(fileindex);
4681 unlockerr = lock_worktree(worktree, LOCK_SH);
4682 if (unlockerr && err == NULL)
4683 err = unlockerr;
4684 return err;
4687 static const struct got_error *
4688 copy_one_line(FILE *infile, FILE *outfile, FILE *rejectfile)
4690 const struct got_error *err = NULL;
4691 char *line = NULL;
4692 size_t linesize = 0, n;
4693 ssize_t linelen;
4695 linelen = getline(&line, &linesize, infile);
4696 if (linelen == -1) {
4697 if (ferror(infile)) {
4698 err = got_error_from_errno("getline");
4699 goto done;
4701 return NULL;
4703 if (outfile) {
4704 n = fwrite(line, 1, linelen, outfile);
4705 if (n != linelen) {
4706 err = got_ferror(outfile, GOT_ERR_IO);
4707 goto done;
4710 if (rejectfile) {
4711 n = fwrite(line, 1, linelen, rejectfile);
4712 if (n != linelen)
4713 err = got_ferror(rejectfile, GOT_ERR_IO);
4715 done:
4716 free(line);
4717 return err;
4720 static const struct got_error *
4721 skip_one_line(FILE *f)
4723 char *line = NULL;
4724 size_t linesize = 0;
4725 ssize_t linelen;
4727 linelen = getline(&line, &linesize, f);
4728 if (linelen == -1) {
4729 if (ferror(f))
4730 return got_error_from_errno("getline");
4731 return NULL;
4733 free(line);
4734 return NULL;
4737 static const struct got_error *
4738 copy_change(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4739 int start_old, int end_old, int start_new, int end_new,
4740 FILE *outfile, FILE *rejectfile)
4742 const struct got_error *err;
4744 /* Copy old file's lines leading up to patch. */
4745 while (!feof(f1) && *line_cur1 < start_old) {
4746 err = copy_one_line(f1, outfile, NULL);
4747 if (err)
4748 return err;
4749 (*line_cur1)++;
4751 /* Skip new file's lines leading up to patch. */
4752 while (!feof(f2) && *line_cur2 < start_new) {
4753 if (rejectfile)
4754 err = copy_one_line(f2, NULL, rejectfile);
4755 else
4756 err = skip_one_line(f2);
4757 if (err)
4758 return err;
4759 (*line_cur2)++;
4761 /* Copy patched lines. */
4762 while (!feof(f2) && *line_cur2 <= end_new) {
4763 err = copy_one_line(f2, outfile, NULL);
4764 if (err)
4765 return err;
4766 (*line_cur2)++;
4768 /* Skip over old file's replaced lines. */
4769 while (!feof(f1) && *line_cur1 <= end_old) {
4770 if (rejectfile)
4771 err = copy_one_line(f1, NULL, rejectfile);
4772 else
4773 err = skip_one_line(f1);
4774 if (err)
4775 return err;
4776 (*line_cur1)++;
4779 return NULL;
4782 static const struct got_error *
4783 copy_remaining_content(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4784 FILE *outfile, FILE *rejectfile)
4786 const struct got_error *err;
4788 if (outfile) {
4789 /* Copy old file's lines until EOF. */
4790 while (!feof(f1)) {
4791 err = copy_one_line(f1, outfile, NULL);
4792 if (err)
4793 return err;
4794 (*line_cur1)++;
4797 if (rejectfile) {
4798 /* Copy new file's lines until EOF. */
4799 while (!feof(f2)) {
4800 err = copy_one_line(f2, NULL, rejectfile);
4801 if (err)
4802 return err;
4803 (*line_cur2)++;
4807 return NULL;
4810 static const struct got_error *
4811 accept_or_reject_binary_change(int *choice, const char *path,
4812 got_worktree_patch_cb patch_cb, void *patch_arg)
4814 const struct got_error *err;
4815 FILE *f;
4817 *choice = GOT_PATCH_CHOICE_NONE;
4819 f = got_opentemp();
4820 if (f == NULL)
4821 return got_error_from_errno("got_opentemp");
4823 if (fprintf(f, "Binary files %s and %s differ\n", path, path) < 0) {
4824 err = got_error_msg(GOT_ERR_IO, "fprintf");
4825 goto done;
4827 if (fseeko(f, 0L, SEEK_SET) == -1) {
4828 err = got_error_from_errno("fseeko");
4829 goto done;
4832 err = (*patch_cb)(choice, patch_arg, GOT_STATUS_MODIFY, path, f, 1, 1);
4834 done:
4835 if (f != NULL && fclose(f) == EOF && err == NULL)
4836 err = got_error_from_errno("fclose");
4837 return err;
4840 static int
4841 diff_result_has_binary(struct diff_result *r)
4843 return (r->left->atomizer_flags | r->right->atomizer_flags) &
4844 DIFF_ATOMIZER_FOUND_BINARY_DATA;
4847 static const struct got_error *
4848 apply_or_reject_change(int *choice, int *nchunks_used,
4849 struct diff_result *diff_result, int n,
4850 const char *relpath, FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4851 FILE *outfile, FILE *rejectfile, int changeno, int nchanges,
4852 got_worktree_patch_cb patch_cb, void *patch_arg)
4854 const struct got_error *err = NULL;
4855 struct diff_chunk_context cc = {};
4856 int start_old, end_old, start_new, end_new;
4857 FILE *hunkfile;
4858 struct diff_output_unidiff_state *diff_state;
4859 struct diff_input_info diff_info;
4860 int rc;
4862 *choice = GOT_PATCH_CHOICE_NONE;
4864 /* Get changed line numbers without context lines for copy_change(). */
4865 diff_chunk_context_load_change(&cc, NULL, diff_result, n, 0);
4866 start_old = cc.left.start;
4867 end_old = cc.left.end;
4868 start_new = cc.right.start;
4869 end_new = cc.right.end;
4871 /* Get the same change with context lines for display. */
4872 memset(&cc, 0, sizeof(cc));
4873 diff_chunk_context_load_change(&cc, nchunks_used, diff_result, n, 3);
4875 memset(&diff_info, 0, sizeof(diff_info));
4876 diff_info.left_path = relpath;
4877 diff_info.right_path = relpath;
4879 diff_state = diff_output_unidiff_state_alloc();
4880 if (diff_state == NULL)
4881 return got_error_set_errno(ENOMEM,
4882 "diff_output_unidiff_state_alloc");
4884 hunkfile = got_opentemp();
4885 if (hunkfile == NULL) {
4886 err = got_error_from_errno("got_opentemp");
4887 goto done;
4890 rc = diff_output_unidiff_chunk(NULL, hunkfile, diff_state, &diff_info,
4891 diff_result, &cc);
4892 if (rc != DIFF_RC_OK) {
4893 err = got_error_set_errno(rc, "diff_output_unidiff_chunk");
4894 goto done;
4897 if (fseek(hunkfile, 0L, SEEK_SET) == -1) {
4898 err = got_ferror(hunkfile, GOT_ERR_IO);
4899 goto done;
4902 err = (*patch_cb)(choice, patch_arg, GOT_STATUS_MODIFY, relpath,
4903 hunkfile, changeno, nchanges);
4904 if (err)
4905 goto done;
4907 switch (*choice) {
4908 case GOT_PATCH_CHOICE_YES:
4909 err = copy_change(f1, f2, line_cur1, line_cur2, start_old,
4910 end_old, start_new, end_new, outfile, rejectfile);
4911 break;
4912 case GOT_PATCH_CHOICE_NO:
4913 err = copy_change(f1, f2, line_cur1, line_cur2, start_old,
4914 end_old, start_new, end_new, rejectfile, outfile);
4915 break;
4916 case GOT_PATCH_CHOICE_QUIT:
4917 break;
4918 default:
4919 err = got_error(GOT_ERR_PATCH_CHOICE);
4920 break;
4922 done:
4923 diff_output_unidiff_state_free(diff_state);
4924 if (hunkfile && fclose(hunkfile) == EOF && err == NULL)
4925 err = got_error_from_errno("fclose");
4926 return err;
4929 struct revert_file_args {
4930 struct got_worktree *worktree;
4931 struct got_fileindex *fileindex;
4932 got_worktree_checkout_cb progress_cb;
4933 void *progress_arg;
4934 got_worktree_patch_cb patch_cb;
4935 void *patch_arg;
4936 struct got_repository *repo;
4937 int unlink_added_files;
4938 struct got_pathlist_head *added_files_to_unlink;
4941 static const struct got_error *
4942 create_patched_content(char **path_outfile, int *confirm_binary_change,
4943 int reverse_patch, struct got_object_id *blob_id, const char *path2,
4944 int dirfd2, const char *de_name2,
4945 const char *relpath, struct got_repository *repo,
4946 got_worktree_patch_cb patch_cb, void *patch_arg)
4948 const struct got_error *err, *free_err;
4949 struct got_blob_object *blob = NULL;
4950 FILE *f1 = NULL, *f2 = NULL, *outfile = NULL;
4951 int fd = -1, fd2 = -1;
4952 char link_target[PATH_MAX];
4953 ssize_t link_len = 0;
4954 char *path1 = NULL, *id_str = NULL;
4955 struct stat sb2;
4956 struct got_diffreg_result *diffreg_result = NULL;
4957 int choice, line_cur1 = 1, line_cur2 = 1, have_content = 0;
4958 int i = 0, n = 0, nchunks_used = 0, nchanges = 0;
4960 *path_outfile = NULL;
4961 *confirm_binary_change = 0;
4963 err = got_object_id_str(&id_str, blob_id);
4964 if (err)
4965 return err;
4967 if (dirfd2 != -1) {
4968 fd2 = openat(dirfd2, de_name2,
4969 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4970 if (fd2 == -1) {
4971 if (!got_err_open_nofollow_on_symlink()) {
4972 err = got_error_from_errno2("openat", path2);
4973 goto done;
4975 link_len = readlinkat(dirfd2, de_name2,
4976 link_target, sizeof(link_target));
4977 if (link_len == -1) {
4978 return got_error_from_errno2("readlinkat",
4979 path2);
4981 sb2.st_mode = S_IFLNK;
4982 sb2.st_size = link_len;
4984 } else {
4985 fd2 = open(path2, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4986 if (fd2 == -1) {
4987 if (!got_err_open_nofollow_on_symlink()) {
4988 err = got_error_from_errno2("open", path2);
4989 goto done;
4991 link_len = readlink(path2, link_target,
4992 sizeof(link_target));
4993 if (link_len == -1)
4994 return got_error_from_errno2("readlink", path2);
4995 sb2.st_mode = S_IFLNK;
4996 sb2.st_size = link_len;
4999 if (fd2 != -1) {
5000 if (fstat(fd2, &sb2) == -1) {
5001 err = got_error_from_errno2("fstat", path2);
5002 goto done;
5005 f2 = fdopen(fd2, "r");
5006 if (f2 == NULL) {
5007 err = got_error_from_errno2("fdopen", path2);
5008 goto done;
5010 fd2 = -1;
5011 } else {
5012 size_t n;
5013 f2 = got_opentemp();
5014 if (f2 == NULL) {
5015 err = got_error_from_errno2("got_opentemp", path2);
5016 goto done;
5018 n = fwrite(link_target, 1, link_len, f2);
5019 if (n != link_len) {
5020 err = got_ferror(f2, GOT_ERR_IO);
5021 goto done;
5023 if (fflush(f2) == EOF) {
5024 err = got_error_from_errno("fflush");
5025 goto done;
5027 rewind(f2);
5030 fd = got_opentempfd();
5031 if (fd == -1) {
5032 err = got_error_from_errno("got_opentempfd");
5033 goto done;
5036 err = got_object_open_as_blob(&blob, repo, blob_id, 8192, fd);
5037 if (err)
5038 goto done;
5040 err = got_opentemp_named(&path1, &f1, "got-patched-blob", "");
5041 if (err)
5042 goto done;
5044 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob);
5045 if (err)
5046 goto done;
5048 err = got_diff_files(&diffreg_result, f1, 1, id_str, f2, 1, path2,
5049 3, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS);
5050 if (err)
5051 goto done;
5053 if (diff_result_has_binary(diffreg_result->result)) {
5054 err = accept_or_reject_binary_change(&choice, relpath,
5055 patch_cb, patch_arg);
5056 if (err == NULL && choice == GOT_PATCH_CHOICE_YES)
5057 *confirm_binary_change = 1;
5058 goto done;
5061 err = got_opentemp_named(path_outfile, &outfile, "got-patched-content",
5062 "");
5063 if (err)
5064 goto done;
5066 if (fseek(f1, 0L, SEEK_SET) == -1)
5067 return got_ferror(f1, GOT_ERR_IO);
5068 if (fseek(f2, 0L, SEEK_SET) == -1)
5069 return got_ferror(f2, GOT_ERR_IO);
5071 /* Count the number of actual changes in the diff result. */
5072 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
5073 struct diff_chunk_context cc = {};
5074 diff_chunk_context_load_change(&cc, &nchunks_used,
5075 diffreg_result->result, n, 0);
5076 nchanges++;
5078 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
5079 err = apply_or_reject_change(&choice, &nchunks_used,
5080 diffreg_result->result, n, relpath, f1, f2,
5081 &line_cur1, &line_cur2,
5082 reverse_patch ? NULL : outfile,
5083 reverse_patch ? outfile : NULL,
5084 ++i, nchanges, patch_cb, patch_arg);
5085 if (err)
5086 goto done;
5087 if (choice == GOT_PATCH_CHOICE_YES)
5088 have_content = 1;
5089 else if (choice == GOT_PATCH_CHOICE_QUIT)
5090 break;
5092 if (have_content) {
5093 err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2,
5094 reverse_patch ? NULL : outfile,
5095 reverse_patch ? outfile : NULL);
5096 if (err)
5097 goto done;
5099 if (!S_ISLNK(sb2.st_mode)) {
5100 mode_t mode;
5102 mode = apply_umask(sb2.st_mode);
5103 if (fchmod(fileno(outfile), mode) == -1) {
5104 err = got_error_from_errno2("fchmod", path2);
5105 goto done;
5109 done:
5110 free(id_str);
5111 if (fd != -1 && close(fd) == -1 && err == NULL)
5112 err = got_error_from_errno("close");
5113 if (blob)
5114 got_object_blob_close(blob);
5115 free_err = got_diffreg_result_free(diffreg_result);
5116 if (err == NULL)
5117 err = free_err;
5118 if (f1 && fclose(f1) == EOF && err == NULL)
5119 err = got_error_from_errno2("fclose", path1);
5120 if (f2 && fclose(f2) == EOF && err == NULL)
5121 err = got_error_from_errno2("fclose", path2);
5122 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
5123 err = got_error_from_errno2("close", path2);
5124 if (outfile && fclose(outfile) == EOF && err == NULL)
5125 err = got_error_from_errno2("fclose", *path_outfile);
5126 if (path1 && unlink(path1) == -1 && err == NULL)
5127 err = got_error_from_errno2("unlink", path1);
5128 if (err || !have_content) {
5129 if (*path_outfile && unlink(*path_outfile) == -1 && err == NULL)
5130 err = got_error_from_errno2("unlink", *path_outfile);
5131 free(*path_outfile);
5132 *path_outfile = NULL;
5134 free(path1);
5135 return err;
5138 static const struct got_error *
5139 revert_file(void *arg, unsigned char status, unsigned char staged_status,
5140 const char *relpath, struct got_object_id *blob_id,
5141 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
5142 int dirfd, const char *de_name)
5144 struct revert_file_args *a = arg;
5145 const struct got_error *err = NULL;
5146 char *parent_path = NULL;
5147 struct got_fileindex_entry *ie;
5148 struct got_commit_object *base_commit = NULL;
5149 struct got_tree_object *tree = NULL;
5150 struct got_object_id *tree_id = NULL;
5151 const struct got_tree_entry *te = NULL;
5152 char *tree_path = NULL, *te_name;
5153 char *ondisk_path = NULL, *path_content = NULL;
5154 struct got_blob_object *blob = NULL;
5155 int fd = -1;
5157 /* Reverting a staged deletion is a no-op. */
5158 if (status == GOT_STATUS_DELETE &&
5159 staged_status != GOT_STATUS_NO_CHANGE)
5160 return NULL;
5162 if (status == GOT_STATUS_UNVERSIONED)
5163 return (*a->progress_cb)(a->progress_arg,
5164 GOT_STATUS_UNVERSIONED, relpath);
5166 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
5167 if (ie == NULL)
5168 return got_error_path(relpath, GOT_ERR_BAD_PATH);
5170 /* Construct in-repository path of tree which contains this blob. */
5171 err = got_path_dirname(&parent_path, ie->path);
5172 if (err) {
5173 if (err->code != GOT_ERR_BAD_PATH)
5174 goto done;
5175 parent_path = strdup("/");
5176 if (parent_path == NULL) {
5177 err = got_error_from_errno("strdup");
5178 goto done;
5181 if (got_path_is_root_dir(a->worktree->path_prefix)) {
5182 tree_path = strdup(parent_path);
5183 if (tree_path == NULL) {
5184 err = got_error_from_errno("strdup");
5185 goto done;
5187 } else {
5188 if (got_path_is_root_dir(parent_path)) {
5189 tree_path = strdup(a->worktree->path_prefix);
5190 if (tree_path == NULL) {
5191 err = got_error_from_errno("strdup");
5192 goto done;
5194 } else {
5195 if (asprintf(&tree_path, "%s/%s",
5196 a->worktree->path_prefix, parent_path) == -1) {
5197 err = got_error_from_errno("asprintf");
5198 goto done;
5203 err = got_object_open_as_commit(&base_commit, a->repo,
5204 a->worktree->base_commit_id);
5205 if (err)
5206 goto done;
5208 err = got_object_id_by_path(&tree_id, a->repo, base_commit, tree_path);
5209 if (err) {
5210 if (!(err->code == GOT_ERR_NO_TREE_ENTRY &&
5211 (status == GOT_STATUS_ADD ||
5212 staged_status == GOT_STATUS_ADD)))
5213 goto done;
5214 } else {
5215 err = got_object_open_as_tree(&tree, a->repo, tree_id);
5216 if (err)
5217 goto done;
5219 err = got_path_basename(&te_name, ie->path);
5220 if (err)
5221 goto done;
5223 te = got_object_tree_find_entry(tree, te_name);
5224 free(te_name);
5225 if (te == NULL && status != GOT_STATUS_ADD &&
5226 staged_status != GOT_STATUS_ADD) {
5227 err = got_error_path(ie->path, GOT_ERR_NO_TREE_ENTRY);
5228 goto done;
5232 switch (status) {
5233 case GOT_STATUS_ADD:
5234 if (a->patch_cb) {
5235 int choice = GOT_PATCH_CHOICE_NONE;
5236 err = (*a->patch_cb)(&choice, a->patch_arg,
5237 status, ie->path, NULL, 1, 1);
5238 if (err)
5239 goto done;
5240 if (choice != GOT_PATCH_CHOICE_YES)
5241 break;
5243 err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_REVERT,
5244 ie->path);
5245 if (err)
5246 goto done;
5247 got_fileindex_entry_remove(a->fileindex, ie);
5248 if (a->unlink_added_files) {
5249 int do_unlink = a->added_files_to_unlink ? 0 : 1;
5251 if (a->added_files_to_unlink) {
5252 struct got_pathlist_entry *pe;
5254 TAILQ_FOREACH(pe, a->added_files_to_unlink,
5255 entry) {
5256 if (got_path_cmp(pe->path, relpath,
5257 pe->path_len, strlen(relpath)))
5258 continue;
5259 do_unlink = 1;
5260 break;
5264 if (do_unlink) {
5265 if (asprintf(&ondisk_path, "%s/%s",
5266 got_worktree_get_root_path(a->worktree),
5267 relpath) == -1) {
5268 err = got_error_from_errno("asprintf");
5269 goto done;
5271 if (unlink(ondisk_path) == -1) {
5272 err = got_error_from_errno2("unlink",
5273 ondisk_path);
5274 break;
5278 break;
5279 case GOT_STATUS_DELETE:
5280 if (a->patch_cb) {
5281 int choice = GOT_PATCH_CHOICE_NONE;
5282 err = (*a->patch_cb)(&choice, a->patch_arg,
5283 status, ie->path, NULL, 1, 1);
5284 if (err)
5285 goto done;
5286 if (choice != GOT_PATCH_CHOICE_YES)
5287 break;
5289 /* fall through */
5290 case GOT_STATUS_MODIFY:
5291 case GOT_STATUS_MODE_CHANGE:
5292 case GOT_STATUS_CONFLICT:
5293 case GOT_STATUS_MISSING: {
5294 struct got_object_id id;
5295 if (staged_status == GOT_STATUS_ADD ||
5296 staged_status == GOT_STATUS_MODIFY)
5297 got_fileindex_entry_get_staged_blob_id(&id, ie);
5298 else
5299 got_fileindex_entry_get_blob_id(&id, ie);
5300 fd = got_opentempfd();
5301 if (fd == -1) {
5302 err = got_error_from_errno("got_opentempfd");
5303 goto done;
5306 err = got_object_open_as_blob(&blob, a->repo, &id, 8192, fd);
5307 if (err)
5308 goto done;
5310 if (asprintf(&ondisk_path, "%s/%s",
5311 got_worktree_get_root_path(a->worktree), relpath) == -1) {
5312 err = got_error_from_errno("asprintf");
5313 goto done;
5316 if (a->patch_cb && (status == GOT_STATUS_MODIFY ||
5317 status == GOT_STATUS_CONFLICT)) {
5318 int is_bad_symlink = 0, revert_binary_file = 0;
5320 err = create_patched_content(&path_content,
5321 &revert_binary_file, 1, &id, ondisk_path, dirfd,
5322 de_name, ie->path, a->repo,
5323 a->patch_cb, a->patch_arg);
5324 if (err != NULL)
5325 goto done;
5326 if (revert_binary_file){
5327 err = install_blob(a->worktree, ondisk_path,
5328 ie->path,
5329 te ? te->mode : GOT_DEFAULT_FILE_MODE,
5330 got_fileindex_perms_to_st(ie), blob,
5331 0, 1, 0, 0, NULL, a->repo,
5332 a->progress_cb, a->progress_arg);
5333 if (err != NULL)
5334 goto done;
5336 if (path_content == NULL)
5337 break;
5338 if (te && S_ISLNK(te->mode)) {
5339 if (unlink(path_content) == -1) {
5340 err = got_error_from_errno2("unlink",
5341 path_content);
5342 break;
5344 err = install_symlink(&is_bad_symlink,
5345 a->worktree, ondisk_path, ie->path,
5346 blob, 0, 1, 0, 0, a->repo,
5347 a->progress_cb, a->progress_arg);
5348 } else {
5349 if (rename(path_content, ondisk_path) == -1) {
5350 err = got_error_from_errno3("rename",
5351 path_content, ondisk_path);
5352 goto done;
5355 } else {
5356 int is_bad_symlink = 0;
5357 if (te && S_ISLNK(te->mode)) {
5358 err = install_symlink(&is_bad_symlink,
5359 a->worktree, ondisk_path, ie->path,
5360 blob, 0, 1, 0, 0, a->repo,
5361 a->progress_cb, a->progress_arg);
5362 } else {
5363 err = install_blob(a->worktree, ondisk_path,
5364 ie->path,
5365 te ? te->mode : GOT_DEFAULT_FILE_MODE,
5366 got_fileindex_perms_to_st(ie), blob,
5367 0, 1, 0, 0, NULL, a->repo,
5368 a->progress_cb, a->progress_arg);
5370 if (err)
5371 goto done;
5372 if (status == GOT_STATUS_DELETE ||
5373 status == GOT_STATUS_MODE_CHANGE) {
5374 err = got_fileindex_entry_update(ie,
5375 a->worktree->root_fd, relpath,
5376 &blob->id, a->worktree->base_commit_id, 1);
5377 if (err)
5378 goto done;
5380 if (is_bad_symlink) {
5381 got_fileindex_entry_filetype_set(ie,
5382 GOT_FILEIDX_MODE_BAD_SYMLINK);
5385 break;
5387 default:
5388 break;
5390 done:
5391 free(ondisk_path);
5392 free(path_content);
5393 free(parent_path);
5394 free(tree_path);
5395 if (fd != -1 && close(fd) == -1 && err == NULL)
5396 err = got_error_from_errno("close");
5397 if (blob)
5398 got_object_blob_close(blob);
5399 if (tree)
5400 got_object_tree_close(tree);
5401 free(tree_id);
5402 if (base_commit)
5403 got_object_commit_close(base_commit);
5404 return err;
5407 const struct got_error *
5408 got_worktree_revert(struct got_worktree *worktree,
5409 struct got_pathlist_head *paths,
5410 got_worktree_checkout_cb progress_cb, void *progress_arg,
5411 got_worktree_patch_cb patch_cb, void *patch_arg,
5412 struct got_repository *repo)
5414 struct got_fileindex *fileindex = NULL;
5415 char *fileindex_path = NULL;
5416 const struct got_error *err = NULL, *unlockerr = NULL;
5417 const struct got_error *sync_err = NULL;
5418 struct got_pathlist_entry *pe;
5419 struct revert_file_args rfa;
5421 err = lock_worktree(worktree, LOCK_EX);
5422 if (err)
5423 return err;
5425 err = open_fileindex(&fileindex, &fileindex_path, worktree,
5426 got_repo_get_object_format(repo));
5427 if (err)
5428 goto done;
5430 rfa.worktree = worktree;
5431 rfa.fileindex = fileindex;
5432 rfa.progress_cb = progress_cb;
5433 rfa.progress_arg = progress_arg;
5434 rfa.patch_cb = patch_cb;
5435 rfa.patch_arg = patch_arg;
5436 rfa.repo = repo;
5437 rfa.unlink_added_files = 0;
5438 TAILQ_FOREACH(pe, paths, entry) {
5439 err = worktree_status(worktree, pe->path, fileindex, repo,
5440 revert_file, &rfa, NULL, NULL, 1, 0);
5441 if (err)
5442 break;
5444 sync_err = sync_fileindex(fileindex, fileindex_path);
5445 if (sync_err && err == NULL)
5446 err = sync_err;
5447 done:
5448 free(fileindex_path);
5449 if (fileindex)
5450 got_fileindex_free(fileindex);
5451 unlockerr = lock_worktree(worktree, LOCK_SH);
5452 if (unlockerr && err == NULL)
5453 err = unlockerr;
5454 return err;
5457 static void
5458 free_commitable(struct got_commitable *ct)
5460 free(ct->path);
5461 free(ct->in_repo_path);
5462 free(ct->ondisk_path);
5463 free(ct->blob_id);
5464 free(ct->base_blob_id);
5465 free(ct->staged_blob_id);
5466 free(ct->base_commit_id);
5467 free(ct);
5470 struct collect_commitables_arg {
5471 struct got_pathlist_head *commitable_paths;
5472 struct got_repository *repo;
5473 struct got_worktree *worktree;
5474 struct got_fileindex *fileindex;
5475 int have_staged_files;
5476 int allow_bad_symlinks;
5477 int diff_header_shown;
5478 int commit_conflicts;
5479 FILE *diff_outfile;
5480 FILE *f1;
5481 FILE *f2;
5485 * Create a file which contains the target path of a symlink so we can feed
5486 * it as content to the diff engine.
5488 static const struct got_error *
5489 get_symlink_target_file(int *fd, int dirfd, const char *de_name,
5490 const char *abspath)
5492 const struct got_error *err = NULL;
5493 char target_path[PATH_MAX];
5494 ssize_t target_len, outlen;
5496 *fd = -1;
5498 if (dirfd != -1) {
5499 target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
5500 if (target_len == -1)
5501 return got_error_from_errno2("readlinkat", abspath);
5502 } else {
5503 target_len = readlink(abspath, target_path, PATH_MAX);
5504 if (target_len == -1)
5505 return got_error_from_errno2("readlink", abspath);
5508 *fd = got_opentempfd();
5509 if (*fd == -1)
5510 return got_error_from_errno("got_opentempfd");
5512 outlen = write(*fd, target_path, target_len);
5513 if (outlen == -1) {
5514 err = got_error_from_errno("got_opentempfd");
5515 goto done;
5518 if (lseek(*fd, 0, SEEK_SET) == -1) {
5519 err = got_error_from_errno2("lseek", abspath);
5520 goto done;
5522 done:
5523 if (err) {
5524 close(*fd);
5525 *fd = -1;
5527 return err;
5530 static const struct got_error *
5531 append_ct_diff(struct got_commitable *ct, int *diff_header_shown,
5532 FILE *diff_outfile, FILE *f1, FILE *f2, int dirfd, const char *de_name,
5533 int diff_staged, struct got_repository *repo, struct got_worktree *worktree)
5535 const struct got_error *err = NULL;
5536 struct got_blob_object *blob1 = NULL;
5537 int fd = -1, fd1 = -1, fd2 = -1;
5538 FILE *ondisk_file = NULL;
5539 char *label1 = NULL;
5540 struct stat sb;
5541 off_t size1 = 0;
5542 int f2_exists = 0;
5543 char *id_str = NULL;
5545 memset(&sb, 0, sizeof(sb));
5547 if (diff_staged) {
5548 if (ct->staged_status != GOT_STATUS_MODIFY &&
5549 ct->staged_status != GOT_STATUS_ADD &&
5550 ct->staged_status != GOT_STATUS_DELETE)
5551 return NULL;
5552 } else {
5553 if (ct->status != GOT_STATUS_MODIFY &&
5554 ct->status != GOT_STATUS_ADD &&
5555 ct->status != GOT_STATUS_DELETE &&
5556 ct->status != GOT_STATUS_CONFLICT)
5557 return NULL;
5560 err = got_opentemp_truncate(f1);
5561 if (err)
5562 return got_error_from_errno("got_opentemp_truncate");
5563 err = got_opentemp_truncate(f2);
5564 if (err)
5565 return got_error_from_errno("got_opentemp_truncate");
5567 if (!*diff_header_shown) {
5568 err = got_object_id_str(&id_str, worktree->base_commit_id);
5569 if (err)
5570 return err;
5571 fprintf(diff_outfile, "diff %s%s\n", diff_staged ? "-s " : "",
5572 got_worktree_get_root_path(worktree));
5573 fprintf(diff_outfile, "commit - %s\n", id_str);
5574 fprintf(diff_outfile, "path + %s%s\n",
5575 got_worktree_get_root_path(worktree),
5576 diff_staged ? " (staged changes)" : "");
5577 *diff_header_shown = 1;
5580 if (diff_staged) {
5581 const char *label1 = NULL, *label2 = NULL;
5582 switch (ct->staged_status) {
5583 case GOT_STATUS_MODIFY:
5584 label1 = ct->path;
5585 label2 = ct->path;
5586 break;
5587 case GOT_STATUS_ADD:
5588 label2 = ct->path;
5589 break;
5590 case GOT_STATUS_DELETE:
5591 label1 = ct->path;
5592 break;
5593 default:
5594 return got_error(GOT_ERR_FILE_STATUS);
5596 fd1 = got_opentempfd();
5597 if (fd1 == -1) {
5598 err = got_error_from_errno("got_opentempfd");
5599 goto done;
5601 fd2 = got_opentempfd();
5602 if (fd2 == -1) {
5603 err = got_error_from_errno("got_opentempfd");
5604 goto done;
5606 err = got_diff_objects_as_blobs(NULL, NULL, f1, f2,
5607 fd1, fd2, ct->base_blob_id, ct->staged_blob_id,
5608 label1, label2, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0,
5609 NULL, repo, diff_outfile);
5610 goto done;
5613 fd1 = got_opentempfd();
5614 if (fd1 == -1) {
5615 err = got_error_from_errno("got_opentempfd");
5616 goto done;
5619 if (ct->status != GOT_STATUS_ADD) {
5620 err = got_object_open_as_blob(&blob1, repo, ct->base_blob_id,
5621 8192, fd1);
5622 if (err)
5623 goto done;
5626 if (ct->status != GOT_STATUS_DELETE) {
5627 if (dirfd != -1) {
5628 fd = openat(dirfd, de_name,
5629 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
5630 if (fd == -1) {
5631 if (!got_err_open_nofollow_on_symlink()) {
5632 err = got_error_from_errno2("openat",
5633 ct->ondisk_path);
5634 goto done;
5636 err = get_symlink_target_file(&fd, dirfd,
5637 de_name, ct->ondisk_path);
5638 if (err)
5639 goto done;
5641 } else {
5642 fd = open(ct->ondisk_path,
5643 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
5644 if (fd == -1) {
5645 if (!got_err_open_nofollow_on_symlink()) {
5646 err = got_error_from_errno2("open",
5647 ct->ondisk_path);
5648 goto done;
5650 err = get_symlink_target_file(&fd, dirfd,
5651 de_name, ct->ondisk_path);
5652 if (err)
5653 goto done;
5656 if (fstatat(fd, ct->ondisk_path, &sb,
5657 AT_SYMLINK_NOFOLLOW) == -1) {
5658 err = got_error_from_errno2("fstatat", ct->ondisk_path);
5659 goto done;
5661 ondisk_file = fdopen(fd, "r");
5662 if (ondisk_file == NULL) {
5663 err = got_error_from_errno2("fdopen", ct->ondisk_path);
5664 goto done;
5666 fd = -1;
5667 f2_exists = 1;
5670 if (blob1) {
5671 err = got_object_blob_dump_to_file(&size1, NULL, NULL,
5672 f1, blob1);
5673 if (err)
5674 goto done;
5677 err = got_diff_blob_file(blob1, f1, size1, label1,
5678 ondisk_file ? ondisk_file : f2, f2_exists, &sb, ct->path,
5679 GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, diff_outfile);
5680 done:
5681 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
5682 err = got_error_from_errno("close");
5683 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
5684 err = got_error_from_errno("close");
5685 if (blob1)
5686 got_object_blob_close(blob1);
5687 if (fd != -1 && close(fd) == -1 && err == NULL)
5688 err = got_error_from_errno("close");
5689 if (ondisk_file && fclose(ondisk_file) == EOF && err == NULL)
5690 err = got_error_from_errno("fclose");
5691 return err;
5694 static const struct got_error *
5695 collect_commitables(void *arg, unsigned char status,
5696 unsigned char staged_status, const char *relpath,
5697 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
5698 struct got_object_id *commit_id, int dirfd, const char *de_name)
5700 struct collect_commitables_arg *a = arg;
5701 const struct got_error *err = NULL;
5702 struct got_commitable *ct = NULL;
5703 struct got_pathlist_entry *new = NULL;
5704 char *parent_path = NULL, *path = NULL;
5705 struct stat sb;
5707 if (a->have_staged_files) {
5708 if (staged_status != GOT_STATUS_MODIFY &&
5709 staged_status != GOT_STATUS_ADD &&
5710 staged_status != GOT_STATUS_DELETE)
5711 return NULL;
5712 } else {
5713 if (status == GOT_STATUS_CONFLICT && !a->commit_conflicts) {
5714 printf("C %s\n", relpath);
5715 return got_error(GOT_ERR_COMMIT_CONFLICT);
5718 if (status != GOT_STATUS_MODIFY &&
5719 status != GOT_STATUS_MODE_CHANGE &&
5720 status != GOT_STATUS_ADD &&
5721 status != GOT_STATUS_DELETE &&
5722 status != GOT_STATUS_CONFLICT)
5723 return NULL;
5726 if (asprintf(&path, "/%s", relpath) == -1) {
5727 err = got_error_from_errno("asprintf");
5728 goto done;
5730 if (strcmp(path, "/") == 0) {
5731 parent_path = strdup("");
5732 if (parent_path == NULL)
5733 return got_error_from_errno("strdup");
5734 } else {
5735 err = got_path_dirname(&parent_path, path);
5736 if (err)
5737 return err;
5740 ct = calloc(1, sizeof(*ct));
5741 if (ct == NULL) {
5742 err = got_error_from_errno("calloc");
5743 goto done;
5746 if (asprintf(&ct->ondisk_path, "%s/%s", a->worktree->root_path,
5747 relpath) == -1) {
5748 err = got_error_from_errno("asprintf");
5749 goto done;
5752 if (staged_status == GOT_STATUS_ADD ||
5753 staged_status == GOT_STATUS_MODIFY) {
5754 struct got_fileindex_entry *ie;
5755 ie = got_fileindex_entry_get(a->fileindex, path, strlen(path));
5756 switch (got_fileindex_entry_staged_filetype_get(ie)) {
5757 case GOT_FILEIDX_MODE_REGULAR_FILE:
5758 case GOT_FILEIDX_MODE_BAD_SYMLINK:
5759 ct->mode = S_IFREG;
5760 break;
5761 case GOT_FILEIDX_MODE_SYMLINK:
5762 ct->mode = S_IFLNK;
5763 break;
5764 default:
5765 err = got_error_path(path, GOT_ERR_BAD_FILETYPE);
5766 goto done;
5768 ct->mode |= got_fileindex_entry_perms_get(ie);
5769 } else if (status != GOT_STATUS_DELETE &&
5770 staged_status != GOT_STATUS_DELETE) {
5771 if (dirfd != -1) {
5772 if (fstatat(dirfd, de_name, &sb,
5773 AT_SYMLINK_NOFOLLOW) == -1) {
5774 err = got_error_from_errno2("fstatat",
5775 ct->ondisk_path);
5776 goto done;
5778 } else if (lstat(ct->ondisk_path, &sb) == -1) {
5779 err = got_error_from_errno2("lstat", ct->ondisk_path);
5780 goto done;
5782 ct->mode = sb.st_mode;
5785 if (asprintf(&ct->in_repo_path, "%s%s%s", a->worktree->path_prefix,
5786 got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/",
5787 relpath) == -1) {
5788 err = got_error_from_errno("asprintf");
5789 goto done;
5792 if (S_ISLNK(ct->mode) && staged_status == GOT_STATUS_NO_CHANGE &&
5793 status == GOT_STATUS_ADD && !a->allow_bad_symlinks) {
5794 int is_bad_symlink;
5795 char target_path[PATH_MAX];
5796 ssize_t target_len;
5797 target_len = readlink(ct->ondisk_path, target_path,
5798 sizeof(target_path));
5799 if (target_len == -1) {
5800 err = got_error_from_errno2("readlink",
5801 ct->ondisk_path);
5802 goto done;
5804 err = is_bad_symlink_target(&is_bad_symlink, target_path,
5805 target_len, ct->ondisk_path, a->worktree->root_path,
5806 a->worktree->meta_dir);
5807 if (err)
5808 goto done;
5809 if (is_bad_symlink) {
5810 err = got_error_path(ct->ondisk_path,
5811 GOT_ERR_BAD_SYMLINK);
5812 goto done;
5817 ct->status = status;
5818 ct->staged_status = staged_status;
5819 ct->blob_id = NULL; /* will be filled in when blob gets created */
5820 if (ct->status != GOT_STATUS_ADD &&
5821 ct->staged_status != GOT_STATUS_ADD) {
5822 ct->base_blob_id = got_object_id_dup(blob_id);
5823 if (ct->base_blob_id == NULL) {
5824 err = got_error_from_errno("got_object_id_dup");
5825 goto done;
5827 ct->base_commit_id = got_object_id_dup(commit_id);
5828 if (ct->base_commit_id == NULL) {
5829 err = got_error_from_errno("got_object_id_dup");
5830 goto done;
5833 if (ct->staged_status == GOT_STATUS_ADD ||
5834 ct->staged_status == GOT_STATUS_MODIFY) {
5835 ct->staged_blob_id = got_object_id_dup(staged_blob_id);
5836 if (ct->staged_blob_id == NULL) {
5837 err = got_error_from_errno("got_object_id_dup");
5838 goto done;
5841 ct->path = strdup(path);
5842 if (ct->path == NULL) {
5843 err = got_error_from_errno("strdup");
5844 goto done;
5847 if (a->diff_outfile) {
5848 err = append_ct_diff(ct, &a->diff_header_shown,
5849 a->diff_outfile, a->f1, a->f2, dirfd, de_name,
5850 a->have_staged_files, a->repo, a->worktree);
5851 if (err)
5852 goto done;
5855 err = got_pathlist_insert(&new, a->commitable_paths, ct->path, ct);
5856 done:
5857 if (ct && (err || new == NULL))
5858 free_commitable(ct);
5859 free(parent_path);
5860 free(path);
5861 return err;
5864 static const struct got_error *write_tree(struct got_object_id **, int *,
5865 struct got_tree_object *, const char *, struct got_pathlist_head *,
5866 got_worktree_status_cb status_cb, void *status_arg,
5867 struct got_repository *);
5869 static const struct got_error *
5870 write_subtree(struct got_object_id **new_subtree_id, int *nentries,
5871 struct got_tree_entry *te, const char *parent_path,
5872 struct got_pathlist_head *commitable_paths,
5873 got_worktree_status_cb status_cb, void *status_arg,
5874 struct got_repository *repo)
5876 const struct got_error *err = NULL;
5877 struct got_tree_object *subtree;
5878 char *subpath;
5880 if (asprintf(&subpath, "%s%s%s", parent_path,
5881 got_path_is_root_dir(parent_path) ? "" : "/", te->name) == -1)
5882 return got_error_from_errno("asprintf");
5884 err = got_object_open_as_tree(&subtree, repo, &te->id);
5885 if (err)
5886 return err;
5888 err = write_tree(new_subtree_id, nentries, subtree, subpath,
5889 commitable_paths, status_cb, status_arg, repo);
5890 got_object_tree_close(subtree);
5891 free(subpath);
5892 return err;
5895 static const struct got_error *
5896 match_ct_parent_path(int *match, struct got_commitable *ct, const char *path)
5898 const struct got_error *err = NULL;
5899 char *ct_parent_path = NULL;
5901 *match = 0;
5903 if (strchr(ct->in_repo_path, '/') == NULL) {
5904 *match = got_path_is_root_dir(path);
5905 return NULL;
5908 err = got_path_dirname(&ct_parent_path, ct->in_repo_path);
5909 if (err)
5910 return err;
5911 *match = (strcmp(path, ct_parent_path) == 0);
5912 free(ct_parent_path);
5913 return err;
5916 static mode_t
5917 get_ct_file_mode(struct got_commitable *ct)
5919 if (S_ISLNK(ct->mode))
5920 return S_IFLNK;
5922 return S_IFREG | (ct->mode & ((S_IRWXU | S_IRWXG | S_IRWXO)));
5925 static const struct got_error *
5926 alloc_modified_blob_tree_entry(struct got_tree_entry **new_te,
5927 struct got_tree_entry *te, struct got_commitable *ct)
5929 const struct got_error *err = NULL;
5931 *new_te = NULL;
5933 err = got_object_tree_entry_dup(new_te, te);
5934 if (err)
5935 goto done;
5937 (*new_te)->mode = get_ct_file_mode(ct);
5939 if (ct->staged_status == GOT_STATUS_MODIFY)
5940 memcpy(&(*new_te)->id, ct->staged_blob_id,
5941 sizeof((*new_te)->id));
5942 else
5943 memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id));
5944 done:
5945 if (err && *new_te) {
5946 free(*new_te);
5947 *new_te = NULL;
5949 return err;
5952 static const struct got_error *
5953 alloc_added_blob_tree_entry(struct got_tree_entry **new_te,
5954 struct got_commitable *ct)
5956 const struct got_error *err = NULL;
5957 char *ct_name = NULL;
5959 *new_te = NULL;
5961 *new_te = calloc(1, sizeof(**new_te));
5962 if (*new_te == NULL)
5963 return got_error_from_errno("calloc");
5965 err = got_path_basename(&ct_name, ct->path);
5966 if (err)
5967 goto done;
5968 if (strlcpy((*new_te)->name, ct_name, sizeof((*new_te)->name)) >=
5969 sizeof((*new_te)->name)) {
5970 err = got_error(GOT_ERR_NO_SPACE);
5971 goto done;
5974 (*new_te)->mode = get_ct_file_mode(ct);
5976 if (ct->staged_status == GOT_STATUS_ADD)
5977 memcpy(&(*new_te)->id, ct->staged_blob_id,
5978 sizeof((*new_te)->id));
5979 else
5980 memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id));
5981 done:
5982 free(ct_name);
5983 if (err && *new_te) {
5984 free(*new_te);
5985 *new_te = NULL;
5987 return err;
5990 static const struct got_error *
5991 insert_tree_entry(struct got_tree_entry *new_te,
5992 struct got_pathlist_head *paths)
5994 const struct got_error *err = NULL;
5995 struct got_pathlist_entry *new_pe;
5997 err = got_pathlist_insert(&new_pe, paths, new_te->name, new_te);
5998 if (err)
5999 return err;
6000 if (new_pe == NULL)
6001 return got_error(GOT_ERR_TREE_DUP_ENTRY);
6002 return NULL;
6005 static const struct got_error *
6006 report_ct_status(struct got_commitable *ct,
6007 got_worktree_status_cb status_cb, void *status_arg)
6009 const char *ct_path = ct->path;
6010 unsigned char status;
6012 if (status_cb == NULL) /* no commit progress output desired */
6013 return NULL;
6015 while (ct_path[0] == '/')
6016 ct_path++;
6018 if (ct->staged_status != GOT_STATUS_NO_CHANGE)
6019 status = ct->staged_status;
6020 else
6021 status = ct->status;
6023 return (*status_cb)(status_arg, status, GOT_STATUS_NO_CHANGE,
6024 ct_path, ct->blob_id, NULL, NULL, -1, NULL);
6027 static const struct got_error *
6028 match_modified_subtree(int *modified, struct got_tree_entry *te,
6029 const char *base_tree_path, struct got_pathlist_head *commitable_paths)
6031 const struct got_error *err = NULL;
6032 struct got_pathlist_entry *pe;
6033 char *te_path;
6035 *modified = 0;
6037 if (asprintf(&te_path, "%s%s%s", base_tree_path,
6038 got_path_is_root_dir(base_tree_path) ? "" : "/",
6039 te->name) == -1)
6040 return got_error_from_errno("asprintf");
6042 TAILQ_FOREACH(pe, commitable_paths, entry) {
6043 struct got_commitable *ct = pe->data;
6044 *modified = got_path_is_child(ct->in_repo_path, te_path,
6045 strlen(te_path));
6046 if (*modified)
6047 break;
6050 free(te_path);
6051 return err;
6054 static const struct got_error *
6055 match_deleted_or_modified_ct(struct got_commitable **ctp,
6056 struct got_tree_entry *te, const char *base_tree_path,
6057 struct got_pathlist_head *commitable_paths)
6059 const struct got_error *err = NULL;
6060 struct got_pathlist_entry *pe;
6062 *ctp = NULL;
6064 TAILQ_FOREACH(pe, commitable_paths, entry) {
6065 struct got_commitable *ct = pe->data;
6066 char *ct_name = NULL;
6067 int path_matches;
6069 if (ct->staged_status == GOT_STATUS_NO_CHANGE) {
6070 if (ct->status != GOT_STATUS_MODIFY &&
6071 ct->status != GOT_STATUS_MODE_CHANGE &&
6072 ct->status != GOT_STATUS_DELETE &&
6073 ct->status != GOT_STATUS_CONFLICT)
6074 continue;
6075 } else {
6076 if (ct->staged_status != GOT_STATUS_MODIFY &&
6077 ct->staged_status != GOT_STATUS_DELETE)
6078 continue;
6081 if (got_object_id_cmp(ct->base_blob_id, &te->id) != 0)
6082 continue;
6084 err = match_ct_parent_path(&path_matches, ct, base_tree_path);
6085 if (err)
6086 return err;
6087 if (!path_matches)
6088 continue;
6090 err = got_path_basename(&ct_name, pe->path);
6091 if (err)
6092 return err;
6094 if (strcmp(te->name, ct_name) != 0) {
6095 free(ct_name);
6096 continue;
6098 free(ct_name);
6100 *ctp = ct;
6101 break;
6104 return err;
6107 static const struct got_error *
6108 make_subtree_for_added_blob(struct got_tree_entry **new_tep,
6109 const char *child_path, const char *path_base_tree,
6110 struct got_pathlist_head *commitable_paths,
6111 got_worktree_status_cb status_cb, void *status_arg,
6112 struct got_repository *repo)
6114 const struct got_error *err = NULL;
6115 struct got_tree_entry *new_te;
6116 char *subtree_path;
6117 struct got_object_id *id = NULL;
6118 int nentries;
6120 *new_tep = NULL;
6122 if (asprintf(&subtree_path, "%s%s%s", path_base_tree,
6123 got_path_is_root_dir(path_base_tree) ? "" : "/",
6124 child_path) == -1)
6125 return got_error_from_errno("asprintf");
6127 new_te = calloc(1, sizeof(*new_te));
6128 if (new_te == NULL)
6129 return got_error_from_errno("calloc");
6130 new_te->mode = S_IFDIR;
6132 if (strlcpy(new_te->name, child_path, sizeof(new_te->name)) >=
6133 sizeof(new_te->name)) {
6134 err = got_error(GOT_ERR_NO_SPACE);
6135 goto done;
6137 err = write_tree(&id, &nentries, NULL, subtree_path,
6138 commitable_paths, status_cb, status_arg, repo);
6139 if (err) {
6140 free(new_te);
6141 goto done;
6143 memcpy(&new_te->id, id, sizeof(new_te->id));
6144 done:
6145 free(id);
6146 free(subtree_path);
6147 if (err == NULL)
6148 *new_tep = new_te;
6149 return err;
6152 static const struct got_error *
6153 write_tree(struct got_object_id **new_tree_id, int *nentries,
6154 struct got_tree_object *base_tree, const char *path_base_tree,
6155 struct got_pathlist_head *commitable_paths,
6156 got_worktree_status_cb status_cb, void *status_arg,
6157 struct got_repository *repo)
6159 const struct got_error *err = NULL;
6160 struct got_pathlist_head paths;
6161 struct got_tree_entry *te, *new_te = NULL;
6162 struct got_pathlist_entry *pe;
6164 TAILQ_INIT(&paths);
6165 *nentries = 0;
6167 /* Insert, and recurse into, newly added entries first. */
6168 TAILQ_FOREACH(pe, commitable_paths, entry) {
6169 struct got_commitable *ct = pe->data;
6170 char *child_path = NULL, *slash;
6172 if ((ct->status != GOT_STATUS_ADD &&
6173 ct->staged_status != GOT_STATUS_ADD) ||
6174 (ct->flags & GOT_COMMITABLE_ADDED))
6175 continue;
6177 if (!got_path_is_child(ct->in_repo_path, path_base_tree,
6178 strlen(path_base_tree)))
6179 continue;
6181 err = got_path_skip_common_ancestor(&child_path, path_base_tree,
6182 ct->in_repo_path);
6183 if (err)
6184 goto done;
6186 slash = strchr(child_path, '/');
6187 if (slash == NULL) {
6188 err = alloc_added_blob_tree_entry(&new_te, ct);
6189 if (err)
6190 goto done;
6191 err = report_ct_status(ct, status_cb, status_arg);
6192 if (err)
6193 goto done;
6194 ct->flags |= GOT_COMMITABLE_ADDED;
6195 err = insert_tree_entry(new_te, &paths);
6196 if (err)
6197 goto done;
6198 (*nentries)++;
6199 } else {
6200 *slash = '\0'; /* trim trailing path components */
6201 if (base_tree == NULL ||
6202 got_object_tree_find_entry(base_tree, child_path)
6203 == NULL) {
6204 err = make_subtree_for_added_blob(&new_te,
6205 child_path, path_base_tree,
6206 commitable_paths, status_cb, status_arg,
6207 repo);
6208 if (err)
6209 goto done;
6210 err = insert_tree_entry(new_te, &paths);
6211 if (err)
6212 goto done;
6213 (*nentries)++;
6218 if (base_tree) {
6219 int i, nbase_entries;
6220 /* Handle modified and deleted entries. */
6221 nbase_entries = got_object_tree_get_nentries(base_tree);
6222 for (i = 0; i < nbase_entries; i++) {
6223 struct got_commitable *ct = NULL;
6225 te = got_object_tree_get_entry(base_tree, i);
6226 if (got_object_tree_entry_is_submodule(te)) {
6227 /* Entry is a submodule; just copy it. */
6228 err = got_object_tree_entry_dup(&new_te, te);
6229 if (err)
6230 goto done;
6231 err = insert_tree_entry(new_te, &paths);
6232 if (err)
6233 goto done;
6234 (*nentries)++;
6235 continue;
6238 if (S_ISDIR(te->mode)) {
6239 int modified;
6240 err = got_object_tree_entry_dup(&new_te, te);
6241 if (err)
6242 goto done;
6243 err = match_modified_subtree(&modified, te,
6244 path_base_tree, commitable_paths);
6245 if (err)
6246 goto done;
6247 /* Avoid recursion into unmodified subtrees. */
6248 if (modified) {
6249 struct got_object_id *new_id;
6250 int nsubentries;
6251 err = write_subtree(&new_id,
6252 &nsubentries, te,
6253 path_base_tree, commitable_paths,
6254 status_cb, status_arg, repo);
6255 if (err)
6256 goto done;
6257 if (nsubentries == 0) {
6258 /* All entries were deleted. */
6259 free(new_id);
6260 continue;
6262 memcpy(&new_te->id, new_id,
6263 sizeof(new_te->id));
6264 free(new_id);
6266 err = insert_tree_entry(new_te, &paths);
6267 if (err)
6268 goto done;
6269 (*nentries)++;
6270 continue;
6273 err = match_deleted_or_modified_ct(&ct, te,
6274 path_base_tree, commitable_paths);
6275 if (err)
6276 goto done;
6277 if (ct) {
6278 /* NB: Deleted entries get dropped here. */
6279 if (ct->status == GOT_STATUS_MODIFY ||
6280 ct->status == GOT_STATUS_MODE_CHANGE ||
6281 ct->status == GOT_STATUS_CONFLICT ||
6282 ct->staged_status == GOT_STATUS_MODIFY) {
6283 err = alloc_modified_blob_tree_entry(
6284 &new_te, te, ct);
6285 if (err)
6286 goto done;
6287 err = insert_tree_entry(new_te, &paths);
6288 if (err)
6289 goto done;
6290 (*nentries)++;
6292 err = report_ct_status(ct, status_cb,
6293 status_arg);
6294 if (err)
6295 goto done;
6296 } else {
6297 /* Entry is unchanged; just copy it. */
6298 err = got_object_tree_entry_dup(&new_te, te);
6299 if (err)
6300 goto done;
6301 err = insert_tree_entry(new_te, &paths);
6302 if (err)
6303 goto done;
6304 (*nentries)++;
6309 /* Write new list of entries; deleted entries have been dropped. */
6310 err = got_object_tree_create(new_tree_id, &paths, *nentries, repo);
6311 done:
6312 got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
6313 return err;
6316 static const struct got_error *
6317 update_fileindex_after_commit(struct got_worktree *worktree,
6318 struct got_pathlist_head *commitable_paths,
6319 struct got_object_id *new_base_commit_id,
6320 struct got_fileindex *fileindex, int have_staged_files)
6322 const struct got_error *err = NULL;
6323 struct got_pathlist_entry *pe;
6324 char *relpath = NULL;
6326 TAILQ_FOREACH(pe, commitable_paths, entry) {
6327 struct got_fileindex_entry *ie;
6328 struct got_commitable *ct = pe->data;
6330 ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len);
6332 err = got_path_skip_common_ancestor(&relpath,
6333 worktree->root_path, ct->ondisk_path);
6334 if (err)
6335 goto done;
6337 if (ie) {
6338 if (ct->status == GOT_STATUS_DELETE ||
6339 ct->staged_status == GOT_STATUS_DELETE) {
6340 got_fileindex_entry_remove(fileindex, ie);
6341 } else if (ct->staged_status == GOT_STATUS_ADD ||
6342 ct->staged_status == GOT_STATUS_MODIFY) {
6343 got_fileindex_entry_stage_set(ie,
6344 GOT_FILEIDX_STAGE_NONE);
6345 got_fileindex_entry_staged_filetype_set(ie, 0);
6347 err = got_fileindex_entry_update(ie,
6348 worktree->root_fd, relpath,
6349 ct->staged_blob_id, new_base_commit_id,
6350 !have_staged_files);
6351 } else
6352 err = got_fileindex_entry_update(ie,
6353 worktree->root_fd, relpath,
6354 ct->blob_id, new_base_commit_id,
6355 !have_staged_files);
6356 } else {
6357 err = got_fileindex_entry_alloc(&ie, pe->path);
6358 if (err)
6359 goto done;
6360 err = got_fileindex_entry_update(ie,
6361 worktree->root_fd, relpath, ct->blob_id,
6362 new_base_commit_id, 1);
6363 if (err) {
6364 got_fileindex_entry_free(ie);
6365 goto done;
6367 err = got_fileindex_entry_add(fileindex, ie);
6368 if (err) {
6369 got_fileindex_entry_free(ie);
6370 goto done;
6373 free(relpath);
6374 relpath = NULL;
6376 done:
6377 free(relpath);
6378 return err;
6382 static const struct got_error *
6383 check_out_of_date(const char *in_repo_path, unsigned char status,
6384 unsigned char staged_status, struct got_object_id *base_blob_id,
6385 struct got_object_id *base_commit_id,
6386 struct got_object_id *head_commit_id, struct got_repository *repo,
6387 int ood_errcode)
6389 const struct got_error *err = NULL;
6390 struct got_commit_object *commit = NULL;
6391 struct got_object_id *id = NULL;
6393 if (status != GOT_STATUS_ADD && staged_status != GOT_STATUS_ADD) {
6394 /* Trivial case: base commit == head commit */
6395 if (got_object_id_cmp(base_commit_id, head_commit_id) == 0)
6396 return NULL;
6398 * Ensure file content which local changes were based
6399 * on matches file content in the branch head.
6401 err = got_object_open_as_commit(&commit, repo, head_commit_id);
6402 if (err)
6403 goto done;
6404 err = got_object_id_by_path(&id, repo, commit, in_repo_path);
6405 if (err) {
6406 if (err->code == GOT_ERR_NO_TREE_ENTRY)
6407 err = got_error(ood_errcode);
6408 goto done;
6409 } else if (got_object_id_cmp(id, base_blob_id) != 0)
6410 err = got_error(ood_errcode);
6411 } else {
6412 /* Require that added files don't exist in the branch head. */
6413 err = got_object_open_as_commit(&commit, repo, head_commit_id);
6414 if (err)
6415 goto done;
6416 err = got_object_id_by_path(&id, repo, commit, in_repo_path);
6417 if (err && err->code != GOT_ERR_NO_TREE_ENTRY)
6418 goto done;
6419 err = id ? got_error(ood_errcode) : NULL;
6421 done:
6422 free(id);
6423 if (commit)
6424 got_object_commit_close(commit);
6425 return err;
6428 static const struct got_error *
6429 commit_worktree(struct got_object_id **new_commit_id,
6430 struct got_pathlist_head *commitable_paths,
6431 struct got_object_id *head_commit_id,
6432 struct got_object_id *parent_id2,
6433 struct got_worktree *worktree,
6434 const char *author, const char *committer, char *diff_path,
6435 got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
6436 got_worktree_status_cb status_cb, void *status_arg,
6437 struct got_repository *repo)
6439 const struct got_error *err = NULL, *unlockerr = NULL;
6440 struct got_pathlist_entry *pe;
6441 const char *head_ref_name = NULL;
6442 struct got_commit_object *head_commit = NULL;
6443 struct got_reference *head_ref2 = NULL;
6444 struct got_object_id *head_commit_id2 = NULL;
6445 struct got_tree_object *head_tree = NULL;
6446 struct got_object_id *new_tree_id = NULL;
6447 int nentries, nparents = 0;
6448 struct got_object_id_queue parent_ids;
6449 struct got_object_qid *pid = NULL;
6450 char *logmsg = NULL;
6451 time_t timestamp;
6453 *new_commit_id = NULL;
6455 STAILQ_INIT(&parent_ids);
6457 err = got_object_open_as_commit(&head_commit, repo, head_commit_id);
6458 if (err)
6459 goto done;
6461 err = got_object_open_as_tree(&head_tree, repo, head_commit->tree_id);
6462 if (err)
6463 goto done;
6465 if (commit_msg_cb != NULL) {
6466 err = commit_msg_cb(commitable_paths, diff_path,
6467 &logmsg, commit_arg);
6468 if (err)
6469 goto done;
6472 if (logmsg == NULL || strlen(logmsg) == 0) {
6473 err = got_error(GOT_ERR_COMMIT_MSG_EMPTY);
6474 goto done;
6477 /* Create blobs from added and modified files and record their IDs. */
6478 TAILQ_FOREACH(pe, commitable_paths, entry) {
6479 struct got_commitable *ct = pe->data;
6480 char *ondisk_path;
6482 /* Blobs for staged files already exist. */
6483 if (ct->staged_status == GOT_STATUS_ADD ||
6484 ct->staged_status == GOT_STATUS_MODIFY)
6485 continue;
6487 if (ct->status != GOT_STATUS_ADD &&
6488 ct->status != GOT_STATUS_MODIFY &&
6489 ct->status != GOT_STATUS_MODE_CHANGE &&
6490 ct->status != GOT_STATUS_CONFLICT)
6491 continue;
6493 if (asprintf(&ondisk_path, "%s/%s",
6494 worktree->root_path, pe->path) == -1) {
6495 err = got_error_from_errno("asprintf");
6496 goto done;
6498 err = got_object_blob_create(&ct->blob_id, ondisk_path, repo);
6499 free(ondisk_path);
6500 if (err)
6501 goto done;
6504 /* Recursively write new tree objects. */
6505 err = write_tree(&new_tree_id, &nentries, head_tree, "/",
6506 commitable_paths, status_cb, status_arg, repo);
6507 if (err)
6508 goto done;
6510 err = got_object_qid_alloc(&pid, head_commit_id);
6511 if (err)
6512 goto done;
6513 STAILQ_INSERT_TAIL(&parent_ids, pid, entry);
6514 nparents++;
6515 if (parent_id2) {
6516 err = got_object_qid_alloc(&pid, parent_id2);
6517 if (err)
6518 goto done;
6519 STAILQ_INSERT_TAIL(&parent_ids, pid, entry);
6520 nparents++;
6522 timestamp = time(NULL);
6523 err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids,
6524 nparents, author, timestamp, committer, timestamp, logmsg, repo);
6525 if (logmsg != NULL)
6526 free(logmsg);
6527 if (err)
6528 goto done;
6530 /* Check if a concurrent commit to our branch has occurred. */
6531 head_ref_name = got_worktree_get_head_ref_name(worktree);
6532 if (head_ref_name == NULL) {
6533 err = got_error_from_errno("got_worktree_get_head_ref_name");
6534 goto done;
6536 /* Lock the reference here to prevent concurrent modification. */
6537 err = got_ref_open(&head_ref2, repo, head_ref_name, 1);
6538 if (err)
6539 goto done;
6540 err = got_ref_resolve(&head_commit_id2, repo, head_ref2);
6541 if (err)
6542 goto done;
6543 if (got_object_id_cmp(head_commit_id, head_commit_id2) != 0) {
6544 err = got_error(GOT_ERR_COMMIT_HEAD_CHANGED);
6545 goto done;
6547 /* Update branch head in repository. */
6548 err = got_ref_change_ref(head_ref2, *new_commit_id);
6549 if (err)
6550 goto done;
6551 err = got_ref_write(head_ref2, repo);
6552 if (err)
6553 goto done;
6555 err = got_worktree_set_base_commit_id(worktree, repo, *new_commit_id);
6556 if (err)
6557 goto done;
6559 err = ref_base_commit(worktree, repo);
6560 if (err)
6561 goto done;
6562 done:
6563 got_object_id_queue_free(&parent_ids);
6564 if (head_tree)
6565 got_object_tree_close(head_tree);
6566 if (head_commit)
6567 got_object_commit_close(head_commit);
6568 free(head_commit_id2);
6569 if (head_ref2) {
6570 unlockerr = got_ref_unlock(head_ref2);
6571 if (unlockerr && err == NULL)
6572 err = unlockerr;
6573 got_ref_close(head_ref2);
6575 return err;
6578 static const struct got_error *
6579 check_path_is_commitable(const char *path,
6580 struct got_pathlist_head *commitable_paths)
6582 struct got_pathlist_entry *cpe = NULL;
6583 size_t path_len = strlen(path);
6585 TAILQ_FOREACH(cpe, commitable_paths, entry) {
6586 struct got_commitable *ct = cpe->data;
6587 const char *ct_path = ct->path;
6589 while (ct_path[0] == '/')
6590 ct_path++;
6592 if (strcmp(path, ct_path) == 0 ||
6593 got_path_is_child(ct_path, path, path_len))
6594 break;
6597 if (cpe == NULL)
6598 return got_error_path(path, GOT_ERR_COMMIT_NO_CHANGES);
6600 return NULL;
6603 static const struct got_error *
6604 check_staged_file(void *arg, struct got_fileindex_entry *ie)
6606 int *have_staged_files = arg;
6608 if (got_fileindex_entry_stage_get(ie) != GOT_FILEIDX_STAGE_NONE) {
6609 *have_staged_files = 1;
6610 return got_error(GOT_ERR_CANCELLED);
6613 return NULL;
6616 static const struct got_error *
6617 check_non_staged_files(struct got_fileindex *fileindex,
6618 struct got_pathlist_head *paths)
6620 struct got_pathlist_entry *pe;
6621 struct got_fileindex_entry *ie;
6623 TAILQ_FOREACH(pe, paths, entry) {
6624 if (pe->path[0] == '\0')
6625 continue;
6626 ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len);
6627 if (ie == NULL)
6628 return got_error_path(pe->path, GOT_ERR_BAD_PATH);
6629 if (got_fileindex_entry_stage_get(ie) == GOT_FILEIDX_STAGE_NONE)
6630 return got_error_path(pe->path,
6631 GOT_ERR_FILE_NOT_STAGED);
6634 return NULL;
6637 const struct got_error *
6638 got_worktree_commit(struct got_object_id **new_commit_id,
6639 struct got_worktree *worktree, struct got_pathlist_head *paths,
6640 const char *author, const char *committer, int allow_bad_symlinks,
6641 int show_diff, int commit_conflicts,
6642 got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
6643 got_worktree_status_cb status_cb, void *status_arg,
6644 struct got_repository *repo)
6646 const struct got_error *err = NULL, *unlockerr = NULL, *sync_err;
6647 struct got_fileindex *fileindex = NULL;
6648 char *fileindex_path = NULL;
6649 struct got_pathlist_head commitable_paths;
6650 struct collect_commitables_arg cc_arg;
6651 struct got_pathlist_entry *pe;
6652 struct got_reference *head_ref = NULL;
6653 struct got_object_id *head_commit_id = NULL;
6654 char *diff_path = NULL;
6655 int have_staged_files = 0;
6657 *new_commit_id = NULL;
6659 memset(&cc_arg, 0, sizeof(cc_arg));
6660 TAILQ_INIT(&commitable_paths);
6662 err = lock_worktree(worktree, LOCK_EX);
6663 if (err)
6664 goto done;
6666 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
6667 if (err)
6668 goto done;
6670 err = got_ref_resolve(&head_commit_id, repo, head_ref);
6671 if (err)
6672 goto done;
6674 err = open_fileindex(&fileindex, &fileindex_path, worktree,
6675 got_repo_get_object_format(repo));
6676 if (err)
6677 goto done;
6679 err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file,
6680 &have_staged_files);
6681 if (err && err->code != GOT_ERR_CANCELLED)
6682 goto done;
6683 if (have_staged_files) {
6684 err = check_non_staged_files(fileindex, paths);
6685 if (err)
6686 goto done;
6689 cc_arg.commitable_paths = &commitable_paths;
6690 cc_arg.worktree = worktree;
6691 cc_arg.fileindex = fileindex;
6692 cc_arg.repo = repo;
6693 cc_arg.have_staged_files = have_staged_files;
6694 cc_arg.allow_bad_symlinks = allow_bad_symlinks;
6695 cc_arg.diff_header_shown = 0;
6696 cc_arg.commit_conflicts = commit_conflicts;
6697 if (show_diff) {
6698 err = got_opentemp_named(&diff_path, &cc_arg.diff_outfile,
6699 GOT_TMPDIR_STR "/got", ".diff");
6700 if (err)
6701 goto done;
6702 cc_arg.f1 = got_opentemp();
6703 if (cc_arg.f1 == NULL) {
6704 err = got_error_from_errno("got_opentemp");
6705 goto done;
6707 cc_arg.f2 = got_opentemp();
6708 if (cc_arg.f2 == NULL) {
6709 err = got_error_from_errno("got_opentemp");
6710 goto done;
6714 TAILQ_FOREACH(pe, paths, entry) {
6715 err = worktree_status(worktree, pe->path, fileindex, repo,
6716 collect_commitables, &cc_arg, NULL, NULL, 0, 0);
6717 if (err)
6718 goto done;
6721 if (show_diff) {
6722 if (fflush(cc_arg.diff_outfile) == EOF) {
6723 err = got_error_from_errno("fflush");
6724 goto done;
6728 if (TAILQ_EMPTY(&commitable_paths)) {
6729 err = got_error(GOT_ERR_COMMIT_NO_CHANGES);
6730 goto done;
6733 TAILQ_FOREACH(pe, paths, entry) {
6734 err = check_path_is_commitable(pe->path, &commitable_paths);
6735 if (err)
6736 goto done;
6739 TAILQ_FOREACH(pe, &commitable_paths, entry) {
6740 struct got_commitable *ct = pe->data;
6741 const char *ct_path = ct->in_repo_path;
6743 while (ct_path[0] == '/')
6744 ct_path++;
6745 err = check_out_of_date(ct_path, ct->status,
6746 ct->staged_status, ct->base_blob_id, ct->base_commit_id,
6747 head_commit_id, repo, GOT_ERR_COMMIT_OUT_OF_DATE);
6748 if (err)
6749 goto done;
6753 err = commit_worktree(new_commit_id, &commitable_paths,
6754 head_commit_id, NULL, worktree, author, committer,
6755 (diff_path && cc_arg.diff_header_shown) ? diff_path : NULL,
6756 commit_msg_cb, commit_arg, status_cb, status_arg, repo);
6757 if (err)
6758 goto done;
6760 err = update_fileindex_after_commit(worktree, &commitable_paths,
6761 *new_commit_id, fileindex, have_staged_files);
6762 sync_err = sync_fileindex(fileindex, fileindex_path);
6763 if (sync_err && err == NULL)
6764 err = sync_err;
6765 done:
6766 if (fileindex)
6767 got_fileindex_free(fileindex);
6768 free(fileindex_path);
6769 unlockerr = lock_worktree(worktree, LOCK_SH);
6770 if (unlockerr && err == NULL)
6771 err = unlockerr;
6772 TAILQ_FOREACH(pe, &commitable_paths, entry) {
6773 struct got_commitable *ct = pe->data;
6775 free_commitable(ct);
6777 got_pathlist_free(&commitable_paths, GOT_PATHLIST_FREE_NONE);
6778 if (diff_path && unlink(diff_path) == -1 && err == NULL)
6779 err = got_error_from_errno2("unlink", diff_path);
6780 free(diff_path);
6781 if (cc_arg.diff_outfile && fclose(cc_arg.diff_outfile) == EOF &&
6782 err == NULL)
6783 err = got_error_from_errno("fclose");
6784 return err;
6787 const char *
6788 got_commitable_get_path(struct got_commitable *ct)
6790 return ct->path;
6793 unsigned int
6794 got_commitable_get_status(struct got_commitable *ct)
6796 return ct->status;
6799 struct check_rebase_ok_arg {
6800 struct got_worktree *worktree;
6801 struct got_repository *repo;
6804 static const struct got_error *
6805 check_rebase_ok(void *arg, struct got_fileindex_entry *ie)
6807 const struct got_error *err = NULL;
6808 struct check_rebase_ok_arg *a = arg;
6809 unsigned char status;
6810 struct stat sb;
6811 char *ondisk_path;
6813 /* Reject rebase of a work tree with mixed base commits. */
6814 if (got_object_id_cmp(&ie->commit, a->worktree->base_commit_id))
6815 return got_error(GOT_ERR_MIXED_COMMITS);
6817 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path)
6818 == -1)
6819 return got_error_from_errno("asprintf");
6821 /* Reject rebase of a work tree with modified or staged files. */
6822 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
6823 free(ondisk_path);
6824 if (err)
6825 return err;
6827 if (status != GOT_STATUS_NO_CHANGE)
6828 return got_error(GOT_ERR_MODIFIED);
6829 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE)
6830 return got_error_path(ie->path, GOT_ERR_FILE_STAGED);
6832 return NULL;
6835 const struct got_error *
6836 got_worktree_rebase_prepare(struct got_reference **new_base_branch_ref,
6837 struct got_reference **tmp_branch, struct got_fileindex **fileindex,
6838 struct got_worktree *worktree, struct got_reference *branch,
6839 struct got_repository *repo)
6841 const struct got_error *err = NULL;
6842 char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL;
6843 char *branch_ref_name = NULL;
6844 char *fileindex_path = NULL;
6845 struct check_rebase_ok_arg ok_arg;
6846 struct got_reference *wt_branch = NULL, *branch_ref = NULL;
6847 struct got_object_id *wt_branch_tip = NULL;
6849 *new_base_branch_ref = NULL;
6850 *tmp_branch = NULL;
6851 *fileindex = NULL;
6853 err = lock_worktree(worktree, LOCK_EX);
6854 if (err)
6855 return err;
6857 err = open_fileindex(fileindex, &fileindex_path, worktree,
6858 got_repo_get_object_format(repo));
6859 if (err)
6860 goto done;
6862 ok_arg.worktree = worktree;
6863 ok_arg.repo = repo;
6864 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
6865 &ok_arg);
6866 if (err)
6867 goto done;
6869 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
6870 if (err)
6871 goto done;
6873 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
6874 if (err)
6875 goto done;
6877 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
6878 if (err)
6879 goto done;
6881 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
6883 if (err)
6884 goto done;
6886 err = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
6887 if (err)
6888 goto done;
6889 if (got_object_id_cmp(worktree->base_commit_id, wt_branch_tip) != 0) {
6890 err = got_error(GOT_ERR_REBASE_OUT_OF_DATE);
6891 goto done;
6894 err = got_ref_alloc_symref(new_base_branch_ref,
6895 new_base_branch_ref_name, wt_branch);
6896 if (err)
6897 goto done;
6898 err = got_ref_write(*new_base_branch_ref, repo);
6899 if (err)
6900 goto done;
6902 /* TODO Lock original branch's ref while rebasing? */
6904 err = got_ref_alloc_symref(&branch_ref, branch_ref_name, branch);
6905 if (err)
6906 goto done;
6908 err = got_ref_write(branch_ref, repo);
6909 if (err)
6910 goto done;
6912 err = got_ref_alloc(tmp_branch, tmp_branch_name,
6913 worktree->base_commit_id);
6914 if (err)
6915 goto done;
6916 err = got_ref_write(*tmp_branch, repo);
6917 if (err)
6918 goto done;
6920 err = got_worktree_set_head_ref(worktree, *tmp_branch);
6921 if (err)
6922 goto done;
6923 done:
6924 free(fileindex_path);
6925 free(tmp_branch_name);
6926 free(new_base_branch_ref_name);
6927 free(branch_ref_name);
6928 if (branch_ref)
6929 got_ref_close(branch_ref);
6930 if (wt_branch)
6931 got_ref_close(wt_branch);
6932 free(wt_branch_tip);
6933 if (err) {
6934 if (*new_base_branch_ref) {
6935 got_ref_close(*new_base_branch_ref);
6936 *new_base_branch_ref = NULL;
6938 if (*tmp_branch) {
6939 got_ref_close(*tmp_branch);
6940 *tmp_branch = NULL;
6942 if (*fileindex) {
6943 got_fileindex_free(*fileindex);
6944 *fileindex = NULL;
6946 lock_worktree(worktree, LOCK_SH);
6948 return err;
6951 const struct got_error *
6952 got_worktree_rebase_continue(struct got_object_id **commit_id,
6953 struct got_reference **new_base_branch, struct got_reference **tmp_branch,
6954 struct got_reference **branch, struct got_fileindex **fileindex,
6955 struct got_worktree *worktree, struct got_repository *repo)
6957 const struct got_error *err;
6958 char *commit_ref_name = NULL, *new_base_branch_ref_name = NULL;
6959 char *tmp_branch_name = NULL, *branch_ref_name = NULL;
6960 struct got_reference *commit_ref = NULL, *branch_ref = NULL;
6961 char *fileindex_path = NULL;
6962 int have_staged_files = 0;
6964 *commit_id = NULL;
6965 *new_base_branch = NULL;
6966 *tmp_branch = NULL;
6967 *branch = NULL;
6968 *fileindex = NULL;
6970 err = lock_worktree(worktree, LOCK_EX);
6971 if (err)
6972 return err;
6974 err = open_fileindex(fileindex, &fileindex_path, worktree,
6975 got_repo_get_object_format(repo));
6976 if (err)
6977 goto done;
6979 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
6980 &have_staged_files);
6981 if (err && err->code != GOT_ERR_CANCELLED)
6982 goto done;
6983 if (have_staged_files) {
6984 err = got_error(GOT_ERR_STAGED_PATHS);
6985 goto done;
6988 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
6989 if (err)
6990 goto done;
6992 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
6993 if (err)
6994 goto done;
6996 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
6997 if (err)
6998 goto done;
7000 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
7001 if (err)
7002 goto done;
7004 err = got_ref_open(&branch_ref, repo, branch_ref_name, 0);
7005 if (err)
7006 goto done;
7008 err = got_ref_open(branch, repo,
7009 got_ref_get_symref_target(branch_ref), 0);
7010 if (err)
7011 goto done;
7013 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
7014 if (err)
7015 goto done;
7017 err = got_ref_resolve(commit_id, repo, commit_ref);
7018 if (err)
7019 goto done;
7021 err = got_ref_open(new_base_branch, repo,
7022 new_base_branch_ref_name, 0);
7023 if (err)
7024 goto done;
7026 err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0);
7027 if (err)
7028 goto done;
7029 done:
7030 free(commit_ref_name);
7031 free(branch_ref_name);
7032 free(fileindex_path);
7033 if (commit_ref)
7034 got_ref_close(commit_ref);
7035 if (branch_ref)
7036 got_ref_close(branch_ref);
7037 if (err) {
7038 free(*commit_id);
7039 *commit_id = NULL;
7040 if (*tmp_branch) {
7041 got_ref_close(*tmp_branch);
7042 *tmp_branch = NULL;
7044 if (*new_base_branch) {
7045 got_ref_close(*new_base_branch);
7046 *new_base_branch = NULL;
7048 if (*branch) {
7049 got_ref_close(*branch);
7050 *branch = NULL;
7052 if (*fileindex) {
7053 got_fileindex_free(*fileindex);
7054 *fileindex = NULL;
7056 lock_worktree(worktree, LOCK_SH);
7058 return err;
7061 const struct got_error *
7062 got_worktree_rebase_in_progress(int *in_progress, struct got_worktree *worktree)
7064 const struct got_error *err;
7065 char *tmp_branch_name = NULL;
7067 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
7068 if (err)
7069 return err;
7071 *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0);
7072 free(tmp_branch_name);
7073 return NULL;
7076 const struct got_error *
7077 got_worktree_rebase_info(char **new_base_branch_name, char **branch_name,
7078 struct got_worktree *worktree, struct got_repository *repo)
7080 const struct got_error *err;
7081 char *new_base_branch_ref_name = NULL;
7082 char *branch_ref_name = NULL;
7083 struct got_reference *branch_ref = NULL, *branch = NULL;
7084 struct got_reference *new_base_branch = NULL;
7086 *new_base_branch_name = NULL;
7087 *branch_name = NULL;
7089 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
7090 if (err)
7091 goto done;
7093 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
7094 if (err)
7095 goto done;
7097 err = got_ref_open(&branch_ref, repo, branch_ref_name, 0);
7098 if (err)
7099 goto done;
7101 err = got_ref_open(&branch, repo,
7102 got_ref_get_symref_target(branch_ref), 0);
7103 if (err)
7104 goto done;
7106 err = got_ref_open(&new_base_branch, repo,
7107 new_base_branch_ref_name, 0);
7108 if (err)
7109 goto done;
7111 if (!got_ref_is_symbolic(new_base_branch)) {
7112 err = got_error_fmt(GOT_ERR_BAD_REF_TYPE,
7113 "%s is not a symbolic reference",
7114 got_ref_get_name(branch_ref));
7115 goto done;
7118 *new_base_branch_name = strdup(got_ref_get_symref_target(
7119 new_base_branch));
7120 if (*new_base_branch_name == NULL) {
7121 err = got_error_from_errno("strdup");
7122 goto done;
7124 *branch_name = strdup(got_ref_get_name(branch));
7125 if (*branch_name == NULL) {
7126 err = got_error_from_errno("strdup");
7127 goto done;
7129 done:
7130 free(branch_ref_name);
7131 if (branch_ref)
7132 got_ref_close(branch_ref);
7133 if (new_base_branch)
7134 got_ref_close(new_base_branch);
7135 if (branch)
7136 got_ref_close(branch);
7137 return err;
7140 static const struct got_error *
7141 collect_rebase_commit_msg(struct got_pathlist_head *commitable_paths,
7142 const char *diff_path, char **logmsg, void *arg)
7144 *logmsg = arg;
7145 return NULL;
7148 static const struct got_error *
7149 rebase_status(void *arg, unsigned char status, unsigned char staged_status,
7150 const char *path, struct got_object_id *blob_id,
7151 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
7152 int dirfd, const char *de_name)
7154 return NULL;
7157 struct collect_merged_paths_arg {
7158 got_worktree_checkout_cb progress_cb;
7159 void *progress_arg;
7160 struct got_pathlist_head *merged_paths;
7163 static const struct got_error *
7164 collect_merged_paths(void *arg, unsigned char status, const char *path)
7166 const struct got_error *err;
7167 struct collect_merged_paths_arg *a = arg;
7168 char *p;
7169 struct got_pathlist_entry *new;
7171 err = (*a->progress_cb)(a->progress_arg, status, path);
7172 if (err)
7173 return err;
7175 if (status != GOT_STATUS_MERGE &&
7176 status != GOT_STATUS_ADD &&
7177 status != GOT_STATUS_DELETE &&
7178 status != GOT_STATUS_CONFLICT)
7179 return NULL;
7181 p = strdup(path);
7182 if (p == NULL)
7183 return got_error_from_errno("strdup");
7185 err = got_pathlist_insert(&new, a->merged_paths, p, NULL);
7186 if (err || new == NULL)
7187 free(p);
7188 return err;
7191 static const struct got_error *
7192 store_commit_id(const char *commit_ref_name, struct got_object_id *commit_id,
7193 int is_rebase, struct got_repository *repo)
7195 const struct got_error *err;
7196 struct got_reference *commit_ref = NULL;
7198 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
7199 if (err) {
7200 if (err->code != GOT_ERR_NOT_REF)
7201 goto done;
7202 err = got_ref_alloc(&commit_ref, commit_ref_name, commit_id);
7203 if (err)
7204 goto done;
7205 err = got_ref_write(commit_ref, repo);
7206 if (err)
7207 goto done;
7208 } else if (is_rebase) {
7209 struct got_object_id *stored_id;
7210 int cmp;
7212 err = got_ref_resolve(&stored_id, repo, commit_ref);
7213 if (err)
7214 goto done;
7215 cmp = got_object_id_cmp(commit_id, stored_id);
7216 free(stored_id);
7217 if (cmp != 0) {
7218 err = got_error(GOT_ERR_REBASE_COMMITID);
7219 goto done;
7222 done:
7223 if (commit_ref)
7224 got_ref_close(commit_ref);
7225 return err;
7228 static const struct got_error *
7229 rebase_merge_files(struct got_pathlist_head *merged_paths,
7230 const char *commit_ref_name, struct got_worktree *worktree,
7231 struct got_fileindex *fileindex, struct got_object_id *parent_commit_id,
7232 struct got_object_id *commit_id, struct got_repository *repo,
7233 got_worktree_checkout_cb progress_cb, void *progress_arg,
7234 got_cancel_cb cancel_cb, void *cancel_arg)
7236 const struct got_error *err;
7237 struct got_reference *commit_ref = NULL;
7238 struct collect_merged_paths_arg cmp_arg;
7239 char *fileindex_path;
7241 /* Work tree is locked/unlocked during rebase preparation/teardown. */
7243 err = get_fileindex_path(&fileindex_path, worktree);
7244 if (err)
7245 return err;
7247 cmp_arg.progress_cb = progress_cb;
7248 cmp_arg.progress_arg = progress_arg;
7249 cmp_arg.merged_paths = merged_paths;
7250 err = merge_files(worktree, fileindex, fileindex_path,
7251 parent_commit_id, commit_id, repo, collect_merged_paths,
7252 &cmp_arg, cancel_cb, cancel_arg);
7253 if (commit_ref)
7254 got_ref_close(commit_ref);
7255 return err;
7258 const struct got_error *
7259 got_worktree_rebase_merge_files(struct got_pathlist_head *merged_paths,
7260 struct got_worktree *worktree, struct got_fileindex *fileindex,
7261 struct got_object_id *parent_commit_id, struct got_object_id *commit_id,
7262 struct got_repository *repo,
7263 got_worktree_checkout_cb progress_cb, void *progress_arg,
7264 got_cancel_cb cancel_cb, void *cancel_arg)
7266 const struct got_error *err;
7267 char *commit_ref_name;
7269 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
7270 if (err)
7271 return err;
7273 err = store_commit_id(commit_ref_name, commit_id, 1, repo);
7274 if (err)
7275 goto done;
7277 err = rebase_merge_files(merged_paths, commit_ref_name, worktree,
7278 fileindex, parent_commit_id, commit_id, repo, progress_cb,
7279 progress_arg, cancel_cb, cancel_arg);
7280 done:
7281 free(commit_ref_name);
7282 return err;
7285 const struct got_error *
7286 got_worktree_histedit_merge_files(struct got_pathlist_head *merged_paths,
7287 struct got_worktree *worktree, struct got_fileindex *fileindex,
7288 struct got_object_id *parent_commit_id, struct got_object_id *commit_id,
7289 struct got_repository *repo,
7290 got_worktree_checkout_cb progress_cb, void *progress_arg,
7291 got_cancel_cb cancel_cb, void *cancel_arg)
7293 const struct got_error *err;
7294 char *commit_ref_name;
7296 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
7297 if (err)
7298 return err;
7300 err = store_commit_id(commit_ref_name, commit_id, 0, repo);
7301 if (err)
7302 goto done;
7304 err = rebase_merge_files(merged_paths, commit_ref_name, worktree,
7305 fileindex, parent_commit_id, commit_id, repo, progress_cb,
7306 progress_arg, cancel_cb, cancel_arg);
7307 done:
7308 free(commit_ref_name);
7309 return err;
7312 static const struct got_error *
7313 rebase_commit(struct got_object_id **new_commit_id,
7314 struct got_pathlist_head *merged_paths, struct got_reference *commit_ref,
7315 struct got_worktree *worktree, struct got_fileindex *fileindex,
7316 struct got_reference *tmp_branch, const char *committer,
7317 struct got_commit_object *orig_commit, const char *new_logmsg,
7318 int allow_conflict, struct got_repository *repo)
7320 const struct got_error *err, *sync_err;
7321 struct got_pathlist_head commitable_paths;
7322 struct collect_commitables_arg cc_arg;
7323 char *fileindex_path = NULL;
7324 struct got_reference *head_ref = NULL;
7325 struct got_object_id *head_commit_id = NULL;
7326 char *logmsg = NULL;
7328 memset(&cc_arg, 0, sizeof(cc_arg));
7329 TAILQ_INIT(&commitable_paths);
7330 *new_commit_id = NULL;
7332 /* Work tree is locked/unlocked during rebase preparation/teardown. */
7334 err = get_fileindex_path(&fileindex_path, worktree);
7335 if (err)
7336 return err;
7338 cc_arg.commitable_paths = &commitable_paths;
7339 cc_arg.worktree = worktree;
7340 cc_arg.repo = repo;
7341 cc_arg.have_staged_files = 0;
7342 cc_arg.commit_conflicts = allow_conflict;
7344 * If possible get the status of individual files directly to
7345 * avoid crawling the entire work tree once per rebased commit.
7347 * Ideally, merged_paths would contain a list of commitables
7348 * we could use so we could skip worktree_status() entirely.
7349 * However, we would then need carefully keep track of cumulative
7350 * effects of operations such as file additions and deletions
7351 * in 'got histedit -f' (folding multiple commits into one),
7352 * and this extra complexity is not really worth it.
7354 if (merged_paths) {
7355 struct got_pathlist_entry *pe;
7356 TAILQ_FOREACH(pe, merged_paths, entry) {
7357 err = worktree_status(worktree, pe->path, fileindex,
7358 repo, collect_commitables, &cc_arg, NULL, NULL, 1,
7360 if (err)
7361 goto done;
7363 } else {
7364 err = worktree_status(worktree, "", fileindex, repo,
7365 collect_commitables, &cc_arg, NULL, NULL, 1, 0);
7366 if (err)
7367 goto done;
7370 if (TAILQ_EMPTY(&commitable_paths)) {
7371 /* No-op change; commit will be elided. */
7372 err = got_ref_delete(commit_ref, repo);
7373 if (err)
7374 goto done;
7375 err = got_error(GOT_ERR_COMMIT_NO_CHANGES);
7376 goto done;
7379 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
7380 if (err)
7381 goto done;
7383 err = got_ref_resolve(&head_commit_id, repo, head_ref);
7384 if (err)
7385 goto done;
7387 if (new_logmsg) {
7388 logmsg = strdup(new_logmsg);
7389 if (logmsg == NULL) {
7390 err = got_error_from_errno("strdup");
7391 goto done;
7393 } else {
7394 err = got_object_commit_get_logmsg(&logmsg, orig_commit);
7395 if (err)
7396 goto done;
7399 /* NB: commit_worktree will call free(logmsg) */
7400 err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id,
7401 NULL, worktree, got_object_commit_get_author(orig_commit),
7402 committer ? committer :
7403 got_object_commit_get_committer(orig_commit), NULL,
7404 collect_rebase_commit_msg, logmsg, rebase_status, NULL, repo);
7405 if (err)
7406 goto done;
7408 err = got_ref_change_ref(tmp_branch, *new_commit_id);
7409 if (err)
7410 goto done;
7412 err = got_ref_delete(commit_ref, repo);
7413 if (err)
7414 goto done;
7416 err = update_fileindex_after_commit(worktree, &commitable_paths,
7417 *new_commit_id, fileindex, 0);
7418 sync_err = sync_fileindex(fileindex, fileindex_path);
7419 if (sync_err && err == NULL)
7420 err = sync_err;
7421 done:
7422 free(fileindex_path);
7423 free(head_commit_id);
7424 if (head_ref)
7425 got_ref_close(head_ref);
7426 if (err) {
7427 free(*new_commit_id);
7428 *new_commit_id = NULL;
7430 return err;
7433 const struct got_error *
7434 got_worktree_rebase_commit(struct got_object_id **new_commit_id,
7435 struct got_pathlist_head *merged_paths, struct got_worktree *worktree,
7436 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
7437 const char *committer, struct got_commit_object *orig_commit,
7438 struct got_object_id *orig_commit_id, int allow_conflict,
7439 struct got_repository *repo)
7441 const struct got_error *err;
7442 char *commit_ref_name;
7443 struct got_reference *commit_ref = NULL;
7444 struct got_object_id *commit_id = NULL;
7446 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
7447 if (err)
7448 return err;
7450 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
7451 if (err)
7452 goto done;
7453 err = got_ref_resolve(&commit_id, repo, commit_ref);
7454 if (err)
7455 goto done;
7456 if (got_object_id_cmp(commit_id, orig_commit_id) != 0) {
7457 err = got_error(GOT_ERR_REBASE_COMMITID);
7458 goto done;
7461 err = rebase_commit(new_commit_id, merged_paths, commit_ref,
7462 worktree, fileindex, tmp_branch, committer, orig_commit,
7463 NULL, allow_conflict, repo);
7464 done:
7465 if (commit_ref)
7466 got_ref_close(commit_ref);
7467 free(commit_ref_name);
7468 free(commit_id);
7469 return err;
7472 const struct got_error *
7473 got_worktree_histedit_commit(struct got_object_id **new_commit_id,
7474 struct got_pathlist_head *merged_paths, struct got_worktree *worktree,
7475 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
7476 const char *committer, struct got_commit_object *orig_commit,
7477 struct got_object_id *orig_commit_id, const char *new_logmsg,
7478 int allow_conflict, struct got_repository *repo)
7480 const struct got_error *err;
7481 char *commit_ref_name;
7482 struct got_reference *commit_ref = NULL;
7484 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
7485 if (err)
7486 return err;
7488 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
7489 if (err)
7490 goto done;
7492 err = rebase_commit(new_commit_id, merged_paths, commit_ref,
7493 worktree, fileindex, tmp_branch, committer, orig_commit,
7494 new_logmsg, allow_conflict, repo);
7495 done:
7496 if (commit_ref)
7497 got_ref_close(commit_ref);
7498 free(commit_ref_name);
7499 return err;
7502 const struct got_error *
7503 got_worktree_rebase_postpone(struct got_worktree *worktree,
7504 struct got_fileindex *fileindex)
7506 if (fileindex)
7507 got_fileindex_free(fileindex);
7508 return lock_worktree(worktree, LOCK_SH);
7511 static const struct got_error *
7512 delete_ref(const char *name, struct got_repository *repo)
7514 const struct got_error *err;
7515 struct got_reference *ref;
7517 err = got_ref_open(&ref, repo, name, 0);
7518 if (err) {
7519 if (err->code == GOT_ERR_NOT_REF)
7520 return NULL;
7521 return err;
7524 err = got_ref_delete(ref, repo);
7525 got_ref_close(ref);
7526 return err;
7529 static const struct got_error *
7530 delete_rebase_refs(struct got_worktree *worktree, struct got_repository *repo)
7532 const struct got_error *err;
7533 char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL;
7534 char *branch_ref_name = NULL, *commit_ref_name = NULL;
7536 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
7537 if (err)
7538 goto done;
7539 err = delete_ref(tmp_branch_name, repo);
7540 if (err)
7541 goto done;
7543 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
7544 if (err)
7545 goto done;
7546 err = delete_ref(new_base_branch_ref_name, repo);
7547 if (err)
7548 goto done;
7550 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
7551 if (err)
7552 goto done;
7553 err = delete_ref(branch_ref_name, repo);
7554 if (err)
7555 goto done;
7557 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
7558 if (err)
7559 goto done;
7560 err = delete_ref(commit_ref_name, repo);
7561 if (err)
7562 goto done;
7564 done:
7565 free(tmp_branch_name);
7566 free(new_base_branch_ref_name);
7567 free(branch_ref_name);
7568 free(commit_ref_name);
7569 return err;
7572 static const struct got_error *
7573 create_backup_ref(const char *backup_ref_prefix, struct got_reference *branch,
7574 struct got_object_id *new_commit_id, struct got_repository *repo)
7576 const struct got_error *err;
7577 struct got_reference *ref = NULL;
7578 struct got_object_id *old_commit_id = NULL;
7579 const char *branch_name = NULL;
7580 char *new_id_str = NULL;
7581 char *refname = NULL;
7583 branch_name = got_ref_get_name(branch);
7584 if (strncmp(branch_name, "refs/heads/", 11) != 0)
7585 return got_error(GOT_ERR_BAD_REF_NAME); /* should not happen */
7586 branch_name += 11;
7588 err = got_object_id_str(&new_id_str, new_commit_id);
7589 if (err)
7590 return err;
7592 if (asprintf(&refname, "%s/%s/%s", backup_ref_prefix, branch_name,
7593 new_id_str) == -1) {
7594 err = got_error_from_errno("asprintf");
7595 goto done;
7598 err = got_ref_resolve(&old_commit_id, repo, branch);
7599 if (err)
7600 goto done;
7602 err = got_ref_alloc(&ref, refname, old_commit_id);
7603 if (err)
7604 goto done;
7606 err = got_ref_write(ref, repo);
7607 done:
7608 free(new_id_str);
7609 free(refname);
7610 free(old_commit_id);
7611 if (ref)
7612 got_ref_close(ref);
7613 return err;
7616 const struct got_error *
7617 got_worktree_rebase_complete(struct got_worktree *worktree,
7618 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
7619 struct got_reference *rebased_branch, struct got_repository *repo,
7620 int create_backup)
7622 const struct got_error *err, *unlockerr, *sync_err;
7623 struct got_object_id *new_head_commit_id = NULL;
7624 char *fileindex_path = NULL;
7626 err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch);
7627 if (err)
7628 return err;
7630 if (create_backup) {
7631 err = create_backup_ref(GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX,
7632 rebased_branch, new_head_commit_id, repo);
7633 if (err)
7634 goto done;
7637 err = got_ref_change_ref(rebased_branch, new_head_commit_id);
7638 if (err)
7639 goto done;
7641 err = got_ref_write(rebased_branch, repo);
7642 if (err)
7643 goto done;
7645 err = got_worktree_set_head_ref(worktree, rebased_branch);
7646 if (err)
7647 goto done;
7649 err = delete_rebase_refs(worktree, repo);
7650 if (err)
7651 goto done;
7653 err = get_fileindex_path(&fileindex_path, worktree);
7654 if (err)
7655 goto done;
7656 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
7657 sync_err = sync_fileindex(fileindex, fileindex_path);
7658 if (sync_err && err == NULL)
7659 err = sync_err;
7660 done:
7661 got_fileindex_free(fileindex);
7662 free(fileindex_path);
7663 free(new_head_commit_id);
7664 unlockerr = lock_worktree(worktree, LOCK_SH);
7665 if (unlockerr && err == NULL)
7666 err = unlockerr;
7667 return err;
7670 static const struct got_error *
7671 get_paths_changed_between_commits(struct got_pathlist_head *paths,
7672 struct got_object_id *id1, struct got_object_id *id2,
7673 struct got_repository *repo)
7675 const struct got_error *err;
7676 struct got_commit_object *commit1 = NULL, *commit2 = NULL;
7677 struct got_tree_object *tree1 = NULL, *tree2 = NULL;
7679 if (id1) {
7680 err = got_object_open_as_commit(&commit1, repo, id1);
7681 if (err)
7682 goto done;
7684 err = got_object_open_as_tree(&tree1, repo,
7685 got_object_commit_get_tree_id(commit1));
7686 if (err)
7687 goto done;
7690 if (id2) {
7691 err = got_object_open_as_commit(&commit2, repo, id2);
7692 if (err)
7693 goto done;
7695 err = got_object_open_as_tree(&tree2, repo,
7696 got_object_commit_get_tree_id(commit2));
7697 if (err)
7698 goto done;
7701 err = got_diff_tree(tree1, tree2, NULL, NULL, -1, -1, "", "", repo,
7702 got_diff_tree_collect_changed_paths, paths, 0);
7703 if (err)
7704 goto done;
7705 done:
7706 if (commit1)
7707 got_object_commit_close(commit1);
7708 if (commit2)
7709 got_object_commit_close(commit2);
7710 if (tree1)
7711 got_object_tree_close(tree1);
7712 if (tree2)
7713 got_object_tree_close(tree2);
7714 return err;
7717 static const struct got_error *
7718 get_paths_added_between_commits(struct got_pathlist_head *added_paths,
7719 struct got_object_id *id1, struct got_object_id *id2,
7720 const char *path_prefix, struct got_repository *repo)
7722 const struct got_error *err;
7723 struct got_pathlist_head merged_paths;
7724 struct got_pathlist_entry *pe;
7725 char *abspath = NULL, *wt_path = NULL;
7727 TAILQ_INIT(&merged_paths);
7729 err = get_paths_changed_between_commits(&merged_paths, id1, id2, repo);
7730 if (err)
7731 goto done;
7733 TAILQ_FOREACH(pe, &merged_paths, entry) {
7734 struct got_diff_changed_path *change = pe->data;
7736 if (change->status != GOT_STATUS_ADD)
7737 continue;
7739 if (got_path_is_root_dir(path_prefix)) {
7740 wt_path = strdup(pe->path);
7741 if (wt_path == NULL) {
7742 err = got_error_from_errno("strdup");
7743 goto done;
7745 } else {
7746 if (asprintf(&abspath, "/%s", pe->path) == -1) {
7747 err = got_error_from_errno("asprintf");
7748 goto done;
7751 err = got_path_skip_common_ancestor(&wt_path,
7752 path_prefix, abspath);
7753 if (err)
7754 goto done;
7755 free(abspath);
7756 abspath = NULL;
7759 err = got_pathlist_insert(NULL, added_paths, wt_path, NULL);
7760 if (err)
7761 goto done;
7762 wt_path = NULL;
7765 done:
7766 got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_ALL);
7767 free(abspath);
7768 free(wt_path);
7769 return err;
7772 static const struct got_error *
7773 get_paths_added_in_commit(struct got_pathlist_head *added_paths,
7774 struct got_object_id *id, const char *path_prefix,
7775 struct got_repository *repo)
7777 const struct got_error *err;
7778 struct got_commit_object *commit = NULL;
7779 struct got_object_qid *pid;
7781 err = got_object_open_as_commit(&commit, repo, id);
7782 if (err)
7783 goto done;
7785 pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
7787 err = get_paths_added_between_commits(added_paths,
7788 pid ? &pid->id : NULL, id, path_prefix, repo);
7789 if (err)
7790 goto done;
7791 done:
7792 if (commit)
7793 got_object_commit_close(commit);
7794 return err;
7797 const struct got_error *
7798 got_worktree_rebase_abort(struct got_worktree *worktree,
7799 struct got_fileindex *fileindex, struct got_repository *repo,
7800 struct got_reference *new_base_branch,
7801 got_worktree_checkout_cb progress_cb, void *progress_arg)
7803 const struct got_error *err, *unlockerr, *sync_err;
7804 struct got_reference *resolved = NULL;
7805 struct got_object_id *commit_id = NULL;
7806 struct got_object_id *merged_commit_id = NULL;
7807 struct got_commit_object *commit = NULL;
7808 char *fileindex_path = NULL;
7809 char *commit_ref_name = NULL;
7810 struct got_reference *commit_ref = NULL;
7811 struct revert_file_args rfa;
7812 struct got_object_id *tree_id = NULL;
7813 struct got_pathlist_head added_paths;
7815 TAILQ_INIT(&added_paths);
7817 err = lock_worktree(worktree, LOCK_EX);
7818 if (err)
7819 return err;
7821 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
7822 if (err)
7823 goto done;
7825 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
7826 if (err)
7827 goto done;
7829 err = got_ref_resolve(&merged_commit_id, repo, commit_ref);
7830 if (err)
7831 goto done;
7834 * Determine which files in added status can be safely removed
7835 * from disk while reverting changes in the work tree.
7836 * We want to avoid deleting unrelated files which were added by
7837 * the user for conflict resolution purposes.
7839 err = get_paths_added_in_commit(&added_paths, merged_commit_id,
7840 got_worktree_get_path_prefix(worktree), repo);
7841 if (err)
7842 goto done;
7844 err = got_ref_open(&resolved, repo,
7845 got_ref_get_symref_target(new_base_branch), 0);
7846 if (err)
7847 goto done;
7849 err = got_worktree_set_head_ref(worktree, resolved);
7850 if (err)
7851 goto done;
7854 * XXX commits to the base branch could have happened while
7855 * we were busy rebasing; should we store the original commit ID
7856 * when rebase begins and read it back here?
7858 err = got_ref_resolve(&commit_id, repo, resolved);
7859 if (err)
7860 goto done;
7862 err = got_worktree_set_base_commit_id(worktree, repo, commit_id);
7863 if (err)
7864 goto done;
7866 err = got_object_open_as_commit(&commit, repo,
7867 worktree->base_commit_id);
7868 if (err)
7869 goto done;
7871 err = got_object_id_by_path(&tree_id, repo, commit,
7872 worktree->path_prefix);
7873 if (err)
7874 goto done;
7876 err = delete_rebase_refs(worktree, repo);
7877 if (err)
7878 goto done;
7880 err = get_fileindex_path(&fileindex_path, worktree);
7881 if (err)
7882 goto done;
7884 rfa.worktree = worktree;
7885 rfa.fileindex = fileindex;
7886 rfa.progress_cb = progress_cb;
7887 rfa.progress_arg = progress_arg;
7888 rfa.patch_cb = NULL;
7889 rfa.patch_arg = NULL;
7890 rfa.repo = repo;
7891 rfa.unlink_added_files = 1;
7892 rfa.added_files_to_unlink = &added_paths;
7893 err = worktree_status(worktree, "", fileindex, repo,
7894 revert_file, &rfa, NULL, NULL, 1, 0);
7895 if (err)
7896 goto sync;
7898 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
7899 repo, progress_cb, progress_arg, NULL, NULL);
7900 sync:
7901 sync_err = sync_fileindex(fileindex, fileindex_path);
7902 if (sync_err && err == NULL)
7903 err = sync_err;
7904 done:
7905 got_pathlist_free(&added_paths, GOT_PATHLIST_FREE_PATH);
7906 got_ref_close(resolved);
7907 free(tree_id);
7908 free(commit_id);
7909 free(merged_commit_id);
7910 if (commit)
7911 got_object_commit_close(commit);
7912 if (fileindex)
7913 got_fileindex_free(fileindex);
7914 free(fileindex_path);
7915 free(commit_ref_name);
7916 if (commit_ref)
7917 got_ref_close(commit_ref);
7919 unlockerr = lock_worktree(worktree, LOCK_SH);
7920 if (unlockerr && err == NULL)
7921 err = unlockerr;
7922 return err;
7925 const struct got_error *
7926 got_worktree_histedit_prepare(struct got_reference **tmp_branch,
7927 struct got_reference **branch_ref, struct got_object_id **base_commit_id,
7928 struct got_fileindex **fileindex, struct got_worktree *worktree,
7929 struct got_repository *repo)
7931 const struct got_error *err = NULL;
7932 char *tmp_branch_name = NULL;
7933 char *branch_ref_name = NULL;
7934 char *base_commit_ref_name = NULL;
7935 char *fileindex_path = NULL;
7936 struct check_rebase_ok_arg ok_arg;
7937 struct got_reference *wt_branch = NULL;
7938 struct got_reference *base_commit_ref = NULL;
7940 *tmp_branch = NULL;
7941 *branch_ref = NULL;
7942 *base_commit_id = NULL;
7943 *fileindex = NULL;
7945 err = lock_worktree(worktree, LOCK_EX);
7946 if (err)
7947 return err;
7949 err = open_fileindex(fileindex, &fileindex_path, worktree,
7950 got_repo_get_object_format(repo));
7951 if (err)
7952 goto done;
7954 ok_arg.worktree = worktree;
7955 ok_arg.repo = repo;
7956 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
7957 &ok_arg);
7958 if (err)
7959 goto done;
7961 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
7962 if (err)
7963 goto done;
7965 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
7966 if (err)
7967 goto done;
7969 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
7970 worktree);
7971 if (err)
7972 goto done;
7974 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
7976 if (err)
7977 goto done;
7979 err = got_ref_alloc_symref(branch_ref, branch_ref_name, wt_branch);
7980 if (err)
7981 goto done;
7983 err = got_ref_write(*branch_ref, repo);
7984 if (err)
7985 goto done;
7987 err = got_ref_alloc(&base_commit_ref, base_commit_ref_name,
7988 worktree->base_commit_id);
7989 if (err)
7990 goto done;
7991 err = got_ref_write(base_commit_ref, repo);
7992 if (err)
7993 goto done;
7994 *base_commit_id = got_object_id_dup(worktree->base_commit_id);
7995 if (*base_commit_id == NULL) {
7996 err = got_error_from_errno("got_object_id_dup");
7997 goto done;
8000 err = got_ref_alloc(tmp_branch, tmp_branch_name,
8001 worktree->base_commit_id);
8002 if (err)
8003 goto done;
8004 err = got_ref_write(*tmp_branch, repo);
8005 if (err)
8006 goto done;
8008 err = got_worktree_set_head_ref(worktree, *tmp_branch);
8009 if (err)
8010 goto done;
8011 done:
8012 free(fileindex_path);
8013 free(tmp_branch_name);
8014 free(branch_ref_name);
8015 free(base_commit_ref_name);
8016 if (wt_branch)
8017 got_ref_close(wt_branch);
8018 if (err) {
8019 if (*branch_ref) {
8020 got_ref_close(*branch_ref);
8021 *branch_ref = NULL;
8023 if (*tmp_branch) {
8024 got_ref_close(*tmp_branch);
8025 *tmp_branch = NULL;
8027 free(*base_commit_id);
8028 if (*fileindex) {
8029 got_fileindex_free(*fileindex);
8030 *fileindex = NULL;
8032 lock_worktree(worktree, LOCK_SH);
8034 return err;
8037 const struct got_error *
8038 got_worktree_histedit_postpone(struct got_worktree *worktree,
8039 struct got_fileindex *fileindex)
8041 if (fileindex)
8042 got_fileindex_free(fileindex);
8043 return lock_worktree(worktree, LOCK_SH);
8046 const struct got_error *
8047 got_worktree_histedit_in_progress(int *in_progress,
8048 struct got_worktree *worktree)
8050 const struct got_error *err;
8051 char *tmp_branch_name = NULL;
8053 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
8054 if (err)
8055 return err;
8057 *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0);
8058 free(tmp_branch_name);
8059 return NULL;
8062 const struct got_error *
8063 got_worktree_histedit_continue(struct got_object_id **commit_id,
8064 struct got_reference **tmp_branch, struct got_reference **branch_ref,
8065 struct got_object_id **base_commit_id, struct got_fileindex **fileindex,
8066 struct got_worktree *worktree, struct got_repository *repo)
8068 const struct got_error *err;
8069 char *commit_ref_name = NULL, *base_commit_ref_name = NULL;
8070 char *tmp_branch_name = NULL, *branch_ref_name = NULL;
8071 struct got_reference *commit_ref = NULL;
8072 struct got_reference *base_commit_ref = NULL;
8073 char *fileindex_path = NULL;
8074 int have_staged_files = 0;
8076 *commit_id = NULL;
8077 *tmp_branch = NULL;
8078 *branch_ref = NULL;
8079 *base_commit_id = NULL;
8080 *fileindex = NULL;
8082 err = lock_worktree(worktree, LOCK_EX);
8083 if (err)
8084 return err;
8086 err = open_fileindex(fileindex, &fileindex_path, worktree,
8087 got_repo_get_object_format(repo));
8088 if (err)
8089 goto done;
8091 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
8092 &have_staged_files);
8093 if (err && err->code != GOT_ERR_CANCELLED)
8094 goto done;
8095 if (have_staged_files) {
8096 err = got_error(GOT_ERR_STAGED_PATHS);
8097 goto done;
8100 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
8101 if (err)
8102 goto done;
8104 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
8105 if (err)
8106 goto done;
8108 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
8109 if (err)
8110 goto done;
8112 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
8113 worktree);
8114 if (err)
8115 goto done;
8117 err = got_ref_open(branch_ref, repo, branch_ref_name, 0);
8118 if (err)
8119 goto done;
8121 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
8122 if (err)
8123 goto done;
8124 err = got_ref_resolve(commit_id, repo, commit_ref);
8125 if (err)
8126 goto done;
8128 err = got_ref_open(&base_commit_ref, repo, base_commit_ref_name, 0);
8129 if (err)
8130 goto done;
8131 err = got_ref_resolve(base_commit_id, repo, base_commit_ref);
8132 if (err)
8133 goto done;
8135 err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0);
8136 if (err)
8137 goto done;
8138 done:
8139 free(commit_ref_name);
8140 free(branch_ref_name);
8141 free(fileindex_path);
8142 if (commit_ref)
8143 got_ref_close(commit_ref);
8144 if (base_commit_ref)
8145 got_ref_close(base_commit_ref);
8146 if (err) {
8147 free(*commit_id);
8148 *commit_id = NULL;
8149 free(*base_commit_id);
8150 *base_commit_id = NULL;
8151 if (*tmp_branch) {
8152 got_ref_close(*tmp_branch);
8153 *tmp_branch = NULL;
8155 if (*branch_ref) {
8156 got_ref_close(*branch_ref);
8157 *branch_ref = NULL;
8159 if (*fileindex) {
8160 got_fileindex_free(*fileindex);
8161 *fileindex = NULL;
8163 lock_worktree(worktree, LOCK_EX);
8165 return err;
8168 const struct got_error *
8169 got_worktree_histedit_info(char **branch_name,
8170 struct got_worktree *worktree, struct got_repository *repo)
8172 const struct got_error *err;
8173 struct got_reference *branch_ref = NULL;
8174 char *branch_ref_name = NULL;
8176 *branch_name = NULL;
8178 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
8179 if (err)
8180 goto done;
8182 err = got_ref_open(&branch_ref, repo, branch_ref_name, 0);
8183 if (err)
8184 goto done;
8186 if (!got_ref_is_symbolic(branch_ref)) {
8187 err = got_error_fmt(GOT_ERR_BAD_REF_TYPE,
8188 "%s is not a symbolic reference",
8189 got_ref_get_name(branch_ref));
8190 goto done;
8193 *branch_name = strdup(got_ref_get_symref_target(branch_ref));
8194 if (*branch_name == NULL) {
8195 err = got_error_from_errno("strdup");
8196 goto done;
8198 done:
8199 free(branch_ref_name);
8200 if (branch_ref)
8201 got_ref_close(branch_ref);
8202 if (err) {
8203 free(*branch_name);
8204 *branch_name = NULL;
8206 return err;
8209 static const struct got_error *
8210 delete_histedit_refs(struct got_worktree *worktree, struct got_repository *repo)
8212 const struct got_error *err;
8213 char *tmp_branch_name = NULL, *base_commit_ref_name = NULL;
8214 char *branch_ref_name = NULL, *commit_ref_name = NULL;
8216 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
8217 if (err)
8218 goto done;
8219 err = delete_ref(tmp_branch_name, repo);
8220 if (err)
8221 goto done;
8223 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
8224 worktree);
8225 if (err)
8226 goto done;
8227 err = delete_ref(base_commit_ref_name, repo);
8228 if (err)
8229 goto done;
8231 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
8232 if (err)
8233 goto done;
8234 err = delete_ref(branch_ref_name, repo);
8235 if (err)
8236 goto done;
8238 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
8239 if (err)
8240 goto done;
8241 err = delete_ref(commit_ref_name, repo);
8242 if (err)
8243 goto done;
8244 done:
8245 free(tmp_branch_name);
8246 free(base_commit_ref_name);
8247 free(branch_ref_name);
8248 free(commit_ref_name);
8249 return err;
8252 const struct got_error *
8253 got_worktree_histedit_abort(struct got_worktree *worktree,
8254 struct got_fileindex *fileindex, struct got_repository *repo,
8255 struct got_reference *branch, struct got_object_id *base_commit_id,
8256 got_worktree_checkout_cb progress_cb, void *progress_arg)
8258 const struct got_error *err, *unlockerr, *sync_err;
8259 struct got_reference *resolved = NULL;
8260 char *fileindex_path = NULL;
8261 struct got_object_id *merged_commit_id = NULL;
8262 struct got_commit_object *commit = NULL;
8263 char *commit_ref_name = NULL;
8264 struct got_reference *commit_ref = NULL;
8265 struct got_object_id *tree_id = NULL;
8266 struct revert_file_args rfa;
8267 struct got_pathlist_head added_paths;
8269 TAILQ_INIT(&added_paths);
8271 err = lock_worktree(worktree, LOCK_EX);
8272 if (err)
8273 return err;
8275 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
8276 if (err)
8277 goto done;
8279 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
8280 if (err) {
8281 if (err->code != GOT_ERR_NOT_REF)
8282 goto done;
8283 /* Can happen on early abort due to invalid histedit script. */
8284 commit_ref = NULL;
8287 if (commit_ref) {
8288 err = got_ref_resolve(&merged_commit_id, repo, commit_ref);
8289 if (err)
8290 goto done;
8293 * Determine which files in added status can be safely removed
8294 * from disk while reverting changes in the work tree.
8295 * We want to avoid deleting unrelated files added by the
8296 * user during conflict resolution or during histedit -e.
8298 err = get_paths_added_in_commit(&added_paths, merged_commit_id,
8299 got_worktree_get_path_prefix(worktree), repo);
8300 if (err)
8301 goto done;
8304 err = got_ref_open(&resolved, repo,
8305 got_ref_get_symref_target(branch), 0);
8306 if (err)
8307 goto done;
8309 err = got_worktree_set_head_ref(worktree, resolved);
8310 if (err)
8311 goto done;
8313 err = got_worktree_set_base_commit_id(worktree, repo, base_commit_id);
8314 if (err)
8315 goto done;
8317 err = got_object_open_as_commit(&commit, repo,
8318 worktree->base_commit_id);
8319 if (err)
8320 goto done;
8322 err = got_object_id_by_path(&tree_id, repo, commit,
8323 worktree->path_prefix);
8324 if (err)
8325 goto done;
8327 err = delete_histedit_refs(worktree, repo);
8328 if (err)
8329 goto done;
8331 err = get_fileindex_path(&fileindex_path, worktree);
8332 if (err)
8333 goto done;
8335 rfa.worktree = worktree;
8336 rfa.fileindex = fileindex;
8337 rfa.progress_cb = progress_cb;
8338 rfa.progress_arg = progress_arg;
8339 rfa.patch_cb = NULL;
8340 rfa.patch_arg = NULL;
8341 rfa.repo = repo;
8342 rfa.unlink_added_files = 1;
8343 rfa.added_files_to_unlink = &added_paths;
8344 err = worktree_status(worktree, "", fileindex, repo,
8345 revert_file, &rfa, NULL, NULL, 1, 0);
8346 if (err)
8347 goto sync;
8349 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
8350 repo, progress_cb, progress_arg, NULL, NULL);
8351 sync:
8352 sync_err = sync_fileindex(fileindex, fileindex_path);
8353 if (sync_err && err == NULL)
8354 err = sync_err;
8355 done:
8356 if (resolved)
8357 got_ref_close(resolved);
8358 if (commit_ref)
8359 got_ref_close(commit_ref);
8360 free(merged_commit_id);
8361 free(tree_id);
8362 free(fileindex_path);
8363 free(commit_ref_name);
8365 unlockerr = lock_worktree(worktree, LOCK_SH);
8366 if (unlockerr && err == NULL)
8367 err = unlockerr;
8368 return err;
8371 const struct got_error *
8372 got_worktree_histedit_complete(struct got_worktree *worktree,
8373 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
8374 struct got_reference *edited_branch, struct got_repository *repo)
8376 const struct got_error *err, *unlockerr, *sync_err;
8377 struct got_object_id *new_head_commit_id = NULL;
8378 struct got_reference *resolved = NULL;
8379 char *fileindex_path = NULL;
8381 err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch);
8382 if (err)
8383 return err;
8385 err = got_ref_open(&resolved, repo,
8386 got_ref_get_symref_target(edited_branch), 0);
8387 if (err)
8388 goto done;
8390 err = create_backup_ref(GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX,
8391 resolved, new_head_commit_id, repo);
8392 if (err)
8393 goto done;
8395 err = got_ref_change_ref(resolved, new_head_commit_id);
8396 if (err)
8397 goto done;
8399 err = got_ref_write(resolved, repo);
8400 if (err)
8401 goto done;
8403 err = got_worktree_set_head_ref(worktree, resolved);
8404 if (err)
8405 goto done;
8407 err = delete_histedit_refs(worktree, repo);
8408 if (err)
8409 goto done;
8411 err = get_fileindex_path(&fileindex_path, worktree);
8412 if (err)
8413 goto done;
8414 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
8415 sync_err = sync_fileindex(fileindex, fileindex_path);
8416 if (sync_err && err == NULL)
8417 err = sync_err;
8418 done:
8419 got_fileindex_free(fileindex);
8420 free(fileindex_path);
8421 free(new_head_commit_id);
8422 unlockerr = lock_worktree(worktree, LOCK_SH);
8423 if (unlockerr && err == NULL)
8424 err = unlockerr;
8425 return err;
8428 const struct got_error *
8429 got_worktree_histedit_skip_commit(struct got_worktree *worktree,
8430 struct got_object_id *commit_id, struct got_repository *repo)
8432 const struct got_error *err;
8433 char *commit_ref_name;
8435 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
8436 if (err)
8437 return err;
8439 err = store_commit_id(commit_ref_name, commit_id, 0, repo);
8440 if (err)
8441 goto done;
8443 err = delete_ref(commit_ref_name, repo);
8444 done:
8445 free(commit_ref_name);
8446 return err;
8449 const struct got_error *
8450 got_worktree_integrate_prepare(struct got_fileindex **fileindex,
8451 struct got_reference **branch_ref, struct got_reference **base_branch_ref,
8452 struct got_worktree *worktree, const char *refname,
8453 struct got_repository *repo)
8455 const struct got_error *err = NULL;
8456 char *fileindex_path = NULL;
8457 struct check_rebase_ok_arg ok_arg;
8459 *fileindex = NULL;
8460 *branch_ref = NULL;
8461 *base_branch_ref = NULL;
8463 err = lock_worktree(worktree, LOCK_EX);
8464 if (err)
8465 return err;
8467 if (strcmp(refname, got_worktree_get_head_ref_name(worktree)) == 0) {
8468 err = got_error_msg(GOT_ERR_SAME_BRANCH,
8469 "cannot integrate a branch into itself; "
8470 "update -b or different branch name required");
8471 goto done;
8474 err = open_fileindex(fileindex, &fileindex_path, worktree,
8475 got_repo_get_object_format(repo));
8476 if (err)
8477 goto done;
8479 /* Preconditions are the same as for rebase. */
8480 ok_arg.worktree = worktree;
8481 ok_arg.repo = repo;
8482 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
8483 &ok_arg);
8484 if (err)
8485 goto done;
8487 err = got_ref_open(branch_ref, repo, refname, 1);
8488 if (err)
8489 goto done;
8491 err = got_ref_open(base_branch_ref, repo,
8492 got_worktree_get_head_ref_name(worktree), 1);
8493 done:
8494 if (err) {
8495 if (*branch_ref) {
8496 got_ref_close(*branch_ref);
8497 *branch_ref = NULL;
8499 if (*base_branch_ref) {
8500 got_ref_close(*base_branch_ref);
8501 *base_branch_ref = NULL;
8503 if (*fileindex) {
8504 got_fileindex_free(*fileindex);
8505 *fileindex = NULL;
8507 lock_worktree(worktree, LOCK_SH);
8509 return err;
8512 const struct got_error *
8513 got_worktree_integrate_continue(struct got_worktree *worktree,
8514 struct got_fileindex *fileindex, struct got_repository *repo,
8515 struct got_reference *branch_ref, struct got_reference *base_branch_ref,
8516 got_worktree_checkout_cb progress_cb, void *progress_arg,
8517 got_cancel_cb cancel_cb, void *cancel_arg)
8519 const struct got_error *err = NULL, *sync_err, *unlockerr;
8520 char *fileindex_path = NULL;
8521 struct got_object_id *tree_id = NULL, *commit_id = NULL;
8522 struct got_commit_object *commit = NULL;
8524 err = get_fileindex_path(&fileindex_path, worktree);
8525 if (err)
8526 goto done;
8528 err = got_ref_resolve(&commit_id, repo, branch_ref);
8529 if (err)
8530 goto done;
8532 err = got_object_open_as_commit(&commit, repo, commit_id);
8533 if (err)
8534 goto done;
8536 err = got_object_id_by_path(&tree_id, repo, commit,
8537 worktree->path_prefix);
8538 if (err)
8539 goto done;
8541 err = got_worktree_set_base_commit_id(worktree, repo, commit_id);
8542 if (err)
8543 goto done;
8545 err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo,
8546 progress_cb, progress_arg, cancel_cb, cancel_arg);
8547 if (err)
8548 goto sync;
8550 err = got_ref_change_ref(base_branch_ref, commit_id);
8551 if (err)
8552 goto sync;
8554 err = got_ref_write(base_branch_ref, repo);
8555 if (err)
8556 goto sync;
8558 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
8559 sync:
8560 sync_err = sync_fileindex(fileindex, fileindex_path);
8561 if (sync_err && err == NULL)
8562 err = sync_err;
8564 done:
8565 unlockerr = got_ref_unlock(branch_ref);
8566 if (unlockerr && err == NULL)
8567 err = unlockerr;
8568 got_ref_close(branch_ref);
8570 unlockerr = got_ref_unlock(base_branch_ref);
8571 if (unlockerr && err == NULL)
8572 err = unlockerr;
8573 got_ref_close(base_branch_ref);
8575 got_fileindex_free(fileindex);
8576 free(fileindex_path);
8577 free(tree_id);
8578 if (commit)
8579 got_object_commit_close(commit);
8581 unlockerr = lock_worktree(worktree, LOCK_SH);
8582 if (unlockerr && err == NULL)
8583 err = unlockerr;
8584 return err;
8587 const struct got_error *
8588 got_worktree_integrate_abort(struct got_worktree *worktree,
8589 struct got_fileindex *fileindex, struct got_repository *repo,
8590 struct got_reference *branch_ref, struct got_reference *base_branch_ref)
8592 const struct got_error *err = NULL, *unlockerr = NULL;
8594 got_fileindex_free(fileindex);
8596 err = lock_worktree(worktree, LOCK_SH);
8598 unlockerr = got_ref_unlock(branch_ref);
8599 if (unlockerr && err == NULL)
8600 err = unlockerr;
8601 got_ref_close(branch_ref);
8603 unlockerr = got_ref_unlock(base_branch_ref);
8604 if (unlockerr && err == NULL)
8605 err = unlockerr;
8606 got_ref_close(base_branch_ref);
8608 return err;
8611 const struct got_error *
8612 got_worktree_merge_postpone(struct got_worktree *worktree,
8613 struct got_fileindex *fileindex)
8615 const struct got_error *err, *sync_err;
8616 char *fileindex_path = NULL;
8618 err = get_fileindex_path(&fileindex_path, worktree);
8619 if (err)
8620 goto done;
8622 sync_err = sync_fileindex(fileindex, fileindex_path);
8624 err = lock_worktree(worktree, LOCK_SH);
8625 if (sync_err && err == NULL)
8626 err = sync_err;
8627 done:
8628 got_fileindex_free(fileindex);
8629 free(fileindex_path);
8630 return err;
8633 static const struct got_error *
8634 delete_merge_refs(struct got_worktree *worktree, struct got_repository *repo)
8636 const struct got_error *err;
8637 char *branch_refname = NULL, *commit_refname = NULL;
8639 err = get_merge_branch_ref_name(&branch_refname, worktree);
8640 if (err)
8641 goto done;
8642 err = delete_ref(branch_refname, repo);
8643 if (err)
8644 goto done;
8646 err = get_merge_commit_ref_name(&commit_refname, worktree);
8647 if (err)
8648 goto done;
8649 err = delete_ref(commit_refname, repo);
8650 if (err)
8651 goto done;
8653 done:
8654 free(branch_refname);
8655 free(commit_refname);
8656 return err;
8659 struct merge_commit_msg_arg {
8660 struct got_worktree *worktree;
8661 const char *branch_name;
8664 static const struct got_error *
8665 merge_commit_msg_cb(struct got_pathlist_head *commitable_paths,
8666 const char *diff_path, char **logmsg, void *arg)
8668 struct merge_commit_msg_arg *a = arg;
8670 if (asprintf(logmsg, "merge %s into %s\n", a->branch_name,
8671 got_worktree_get_head_ref_name(a->worktree)) == -1)
8672 return got_error_from_errno("asprintf");
8674 return NULL;
8678 const struct got_error *
8679 got_worktree_merge_branch(struct got_worktree *worktree,
8680 struct got_fileindex *fileindex,
8681 struct got_object_id *yca_commit_id,
8682 struct got_object_id *branch_tip,
8683 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
8684 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
8686 const struct got_error *err;
8687 char *fileindex_path = NULL;
8688 struct check_mixed_commits_args cma;
8690 err = get_fileindex_path(&fileindex_path, worktree);
8691 if (err)
8692 goto done;
8694 cma.worktree = worktree;
8695 cma.cancel_cb = cancel_cb;
8696 cma.cancel_arg = cancel_arg;
8698 err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits,
8699 &cma);
8700 if (err)
8701 goto done;
8703 err = merge_files(worktree, fileindex, fileindex_path, yca_commit_id,
8704 branch_tip, repo, progress_cb, progress_arg,
8705 cancel_cb, cancel_arg);
8706 done:
8707 free(fileindex_path);
8708 return err;
8711 const struct got_error *
8712 got_worktree_merge_commit(struct got_object_id **new_commit_id,
8713 struct got_worktree *worktree, struct got_fileindex *fileindex,
8714 const char *author, const char *committer, int allow_bad_symlinks,
8715 struct got_object_id *branch_tip, const char *branch_name,
8716 int allow_conflict, struct got_repository *repo,
8717 got_worktree_status_cb status_cb, void *status_arg)
8720 const struct got_error *err = NULL, *sync_err;
8721 struct got_pathlist_head commitable_paths;
8722 struct collect_commitables_arg cc_arg;
8723 struct got_pathlist_entry *pe;
8724 struct got_reference *head_ref = NULL;
8725 struct got_object_id *head_commit_id = NULL;
8726 int have_staged_files = 0;
8727 struct merge_commit_msg_arg mcm_arg;
8728 char *fileindex_path = NULL;
8730 memset(&cc_arg, 0, sizeof(cc_arg));
8731 *new_commit_id = NULL;
8733 TAILQ_INIT(&commitable_paths);
8735 err = get_fileindex_path(&fileindex_path, worktree);
8736 if (err)
8737 goto done;
8739 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
8740 if (err)
8741 goto done;
8743 err = got_ref_resolve(&head_commit_id, repo, head_ref);
8744 if (err)
8745 goto done;
8747 err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file,
8748 &have_staged_files);
8749 if (err && err->code != GOT_ERR_CANCELLED)
8750 goto done;
8751 if (have_staged_files) {
8752 err = got_error(GOT_ERR_MERGE_STAGED_PATHS);
8753 goto done;
8756 cc_arg.commitable_paths = &commitable_paths;
8757 cc_arg.worktree = worktree;
8758 cc_arg.fileindex = fileindex;
8759 cc_arg.repo = repo;
8760 cc_arg.have_staged_files = have_staged_files;
8761 cc_arg.allow_bad_symlinks = allow_bad_symlinks;
8762 cc_arg.commit_conflicts = allow_conflict;
8763 err = worktree_status(worktree, "", fileindex, repo,
8764 collect_commitables, &cc_arg, NULL, NULL, 1, 0);
8765 if (err)
8766 goto done;
8768 mcm_arg.worktree = worktree;
8769 mcm_arg.branch_name = branch_name;
8770 err = commit_worktree(new_commit_id, &commitable_paths,
8771 head_commit_id, branch_tip, worktree, author, committer, NULL,
8772 merge_commit_msg_cb, &mcm_arg, status_cb, status_arg, repo);
8773 if (err)
8774 goto done;
8776 err = update_fileindex_after_commit(worktree, &commitable_paths,
8777 *new_commit_id, fileindex, have_staged_files);
8778 sync_err = sync_fileindex(fileindex, fileindex_path);
8779 if (sync_err && err == NULL)
8780 err = sync_err;
8781 done:
8782 TAILQ_FOREACH(pe, &commitable_paths, entry) {
8783 struct got_commitable *ct = pe->data;
8785 free_commitable(ct);
8787 got_pathlist_free(&commitable_paths, GOT_PATHLIST_FREE_NONE);
8788 free(fileindex_path);
8789 return err;
8792 const struct got_error *
8793 got_worktree_merge_complete(struct got_worktree *worktree,
8794 struct got_fileindex *fileindex, struct got_repository *repo)
8796 const struct got_error *err, *unlockerr, *sync_err;
8797 char *fileindex_path = NULL;
8799 err = delete_merge_refs(worktree, repo);
8800 if (err)
8801 goto done;
8803 err = get_fileindex_path(&fileindex_path, worktree);
8804 if (err)
8805 goto done;
8806 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
8807 sync_err = sync_fileindex(fileindex, fileindex_path);
8808 if (sync_err && err == NULL)
8809 err = sync_err;
8810 done:
8811 got_fileindex_free(fileindex);
8812 free(fileindex_path);
8813 unlockerr = lock_worktree(worktree, LOCK_SH);
8814 if (unlockerr && err == NULL)
8815 err = unlockerr;
8816 return err;
8819 const struct got_error *
8820 got_worktree_merge_in_progress(int *in_progress, struct got_worktree *worktree,
8821 struct got_repository *repo)
8823 const struct got_error *err;
8824 char *branch_refname = NULL;
8825 struct got_reference *branch_ref = NULL;
8827 *in_progress = 0;
8829 err = get_merge_branch_ref_name(&branch_refname, worktree);
8830 if (err)
8831 return err;
8832 err = got_ref_open(&branch_ref, repo, branch_refname, 0);
8833 free(branch_refname);
8834 if (err) {
8835 if (err->code != GOT_ERR_NOT_REF)
8836 return err;
8837 } else
8838 *in_progress = 1;
8840 return NULL;
8843 const struct got_error *got_worktree_merge_prepare(
8844 struct got_fileindex **fileindex, struct got_worktree *worktree,
8845 struct got_repository *repo)
8847 const struct got_error *err = NULL;
8848 char *fileindex_path = NULL;
8849 struct got_reference *wt_branch = NULL;
8850 struct got_object_id *wt_branch_tip = NULL;
8851 struct check_rebase_ok_arg ok_arg;
8853 *fileindex = NULL;
8855 err = lock_worktree(worktree, LOCK_EX);
8856 if (err)
8857 return err;
8859 err = open_fileindex(fileindex, &fileindex_path, worktree,
8860 got_repo_get_object_format(repo));
8861 if (err)
8862 goto done;
8864 /* Preconditions are the same as for rebase. */
8865 ok_arg.worktree = worktree;
8866 ok_arg.repo = repo;
8867 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
8868 &ok_arg);
8869 if (err)
8870 goto done;
8872 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
8874 if (err)
8875 goto done;
8877 err = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
8878 if (err)
8879 goto done;
8881 if (got_object_id_cmp(worktree->base_commit_id, wt_branch_tip) != 0) {
8882 err = got_error(GOT_ERR_MERGE_OUT_OF_DATE);
8883 goto done;
8886 done:
8887 free(fileindex_path);
8888 if (wt_branch)
8889 got_ref_close(wt_branch);
8890 free(wt_branch_tip);
8891 if (err) {
8892 if (*fileindex) {
8893 got_fileindex_free(*fileindex);
8894 *fileindex = NULL;
8896 lock_worktree(worktree, LOCK_SH);
8898 return err;
8901 const struct got_error *got_worktree_merge_write_refs(
8902 struct got_worktree *worktree, struct got_reference *branch,
8903 struct got_repository *repo)
8905 const struct got_error *err = NULL;
8906 char *branch_refname = NULL, *commit_refname = NULL;
8907 struct got_reference *branch_ref = NULL, *commit_ref = NULL;
8908 struct got_object_id *branch_tip = NULL;
8910 err = get_merge_branch_ref_name(&branch_refname, worktree);
8911 if (err)
8912 return err;
8914 err = get_merge_commit_ref_name(&commit_refname, worktree);
8915 if (err)
8916 return err;
8918 err = got_ref_resolve(&branch_tip, repo, branch);
8919 if (err)
8920 goto done;
8922 err = got_ref_alloc_symref(&branch_ref, branch_refname, branch);
8923 if (err)
8924 goto done;
8925 err = got_ref_write(branch_ref, repo);
8926 if (err)
8927 goto done;
8929 err = got_ref_alloc(&commit_ref, commit_refname, branch_tip);
8930 if (err)
8931 goto done;
8932 err = got_ref_write(commit_ref, repo);
8933 if (err)
8934 goto done;
8936 done:
8937 free(branch_refname);
8938 free(commit_refname);
8939 if (branch_ref)
8940 got_ref_close(branch_ref);
8941 if (commit_ref)
8942 got_ref_close(commit_ref);
8943 free(branch_tip);
8944 return err;
8947 const struct got_error *
8948 got_worktree_merge_continue(char **branch_name,
8949 struct got_object_id **branch_tip, struct got_fileindex **fileindex,
8950 struct got_worktree *worktree, struct got_repository *repo)
8952 const struct got_error *err;
8953 char *commit_refname = NULL, *branch_refname = NULL;
8954 struct got_reference *commit_ref = NULL, *branch_ref = NULL;
8955 char *fileindex_path = NULL;
8956 int have_staged_files = 0;
8958 *branch_name = NULL;
8959 *branch_tip = NULL;
8960 *fileindex = NULL;
8962 err = lock_worktree(worktree, LOCK_EX);
8963 if (err)
8964 return err;
8966 err = open_fileindex(fileindex, &fileindex_path, worktree,
8967 got_repo_get_object_format(repo));
8968 if (err)
8969 goto done;
8971 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
8972 &have_staged_files);
8973 if (err && err->code != GOT_ERR_CANCELLED)
8974 goto done;
8975 if (have_staged_files) {
8976 err = got_error(GOT_ERR_STAGED_PATHS);
8977 goto done;
8980 err = get_merge_branch_ref_name(&branch_refname, worktree);
8981 if (err)
8982 goto done;
8984 err = get_merge_commit_ref_name(&commit_refname, worktree);
8985 if (err)
8986 goto done;
8988 err = got_ref_open(&branch_ref, repo, branch_refname, 0);
8989 if (err)
8990 goto done;
8992 if (!got_ref_is_symbolic(branch_ref)) {
8993 err = got_error_fmt(GOT_ERR_BAD_REF_TYPE,
8994 "%s is not a symbolic reference",
8995 got_ref_get_name(branch_ref));
8996 goto done;
8998 *branch_name = strdup(got_ref_get_symref_target(branch_ref));
8999 if (*branch_name == NULL) {
9000 err = got_error_from_errno("strdup");
9001 goto done;
9004 err = got_ref_open(&commit_ref, repo, commit_refname, 0);
9005 if (err)
9006 goto done;
9008 err = got_ref_resolve(branch_tip, repo, commit_ref);
9009 if (err)
9010 goto done;
9011 done:
9012 free(commit_refname);
9013 free(branch_refname);
9014 free(fileindex_path);
9015 if (commit_ref)
9016 got_ref_close(commit_ref);
9017 if (branch_ref)
9018 got_ref_close(branch_ref);
9019 if (err) {
9020 if (*branch_name) {
9021 free(*branch_name);
9022 *branch_name = NULL;
9024 free(*branch_tip);
9025 *branch_tip = NULL;
9026 if (*fileindex) {
9027 got_fileindex_free(*fileindex);
9028 *fileindex = NULL;
9030 lock_worktree(worktree, LOCK_SH);
9032 return err;
9035 const struct got_error *
9036 got_worktree_merge_info(char **branch_name, struct got_worktree *worktree,
9037 struct got_repository *repo)
9039 const struct got_error *err;
9040 char *branch_refname = NULL;
9041 struct got_reference *branch_ref = NULL;
9043 *branch_name = NULL;
9045 err = get_merge_branch_ref_name(&branch_refname, worktree);
9046 if (err)
9047 goto done;
9049 err = got_ref_open(&branch_ref, repo, branch_refname, 0);
9050 if (err)
9051 goto done;
9053 if (!got_ref_is_symbolic(branch_ref)) {
9054 err = got_error_fmt(GOT_ERR_BAD_REF_TYPE,
9055 "%s is not a symbolic reference",
9056 got_ref_get_name(branch_ref));
9057 goto done;
9059 *branch_name = strdup(got_ref_get_symref_target(branch_ref));
9060 if (*branch_name == NULL) {
9061 err = got_error_from_errno("strdup");
9062 goto done;
9065 done:
9066 free(branch_refname);
9067 if (branch_ref)
9068 got_ref_close(branch_ref);
9069 if (err) {
9070 if (*branch_name) {
9071 free(*branch_name);
9072 *branch_name = NULL;
9075 return err;
9078 const struct got_error *
9079 got_worktree_merge_abort(struct got_worktree *worktree,
9080 struct got_fileindex *fileindex, struct got_repository *repo,
9081 got_worktree_checkout_cb progress_cb, void *progress_arg)
9083 const struct got_error *err, *unlockerr, *sync_err;
9084 struct got_commit_object *commit = NULL;
9085 char *fileindex_path = NULL;
9086 struct revert_file_args rfa;
9087 char *commit_ref_name = NULL;
9088 struct got_reference *commit_ref = NULL;
9089 struct got_object_id *merged_commit_id = NULL;
9090 struct got_object_id *tree_id = NULL;
9091 struct got_pathlist_head added_paths;
9093 TAILQ_INIT(&added_paths);
9095 err = get_merge_commit_ref_name(&commit_ref_name, worktree);
9096 if (err)
9097 goto done;
9099 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
9100 if (err)
9101 goto done;
9103 err = got_ref_resolve(&merged_commit_id, repo, commit_ref);
9104 if (err)
9105 goto done;
9108 * Determine which files in added status can be safely removed
9109 * from disk while reverting changes in the work tree.
9110 * We want to avoid deleting unrelated files which were added by
9111 * the user for conflict resolution purposes.
9113 err = get_paths_added_between_commits(&added_paths,
9114 got_worktree_get_base_commit_id(worktree), merged_commit_id,
9115 got_worktree_get_path_prefix(worktree), repo);
9116 if (err)
9117 goto done;
9120 err = got_object_open_as_commit(&commit, repo,
9121 worktree->base_commit_id);
9122 if (err)
9123 goto done;
9125 err = got_object_id_by_path(&tree_id, repo, commit,
9126 worktree->path_prefix);
9127 if (err)
9128 goto done;
9130 err = delete_merge_refs(worktree, repo);
9131 if (err)
9132 goto done;
9134 err = get_fileindex_path(&fileindex_path, worktree);
9135 if (err)
9136 goto done;
9138 rfa.worktree = worktree;
9139 rfa.fileindex = fileindex;
9140 rfa.progress_cb = progress_cb;
9141 rfa.progress_arg = progress_arg;
9142 rfa.patch_cb = NULL;
9143 rfa.patch_arg = NULL;
9144 rfa.repo = repo;
9145 rfa.unlink_added_files = 1;
9146 rfa.added_files_to_unlink = &added_paths;
9147 err = worktree_status(worktree, "", fileindex, repo,
9148 revert_file, &rfa, NULL, NULL, 1, 0);
9149 if (err)
9150 goto sync;
9152 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
9153 repo, progress_cb, progress_arg, NULL, NULL);
9154 sync:
9155 sync_err = sync_fileindex(fileindex, fileindex_path);
9156 if (sync_err && err == NULL)
9157 err = sync_err;
9158 done:
9159 free(tree_id);
9160 free(merged_commit_id);
9161 if (commit)
9162 got_object_commit_close(commit);
9163 if (fileindex)
9164 got_fileindex_free(fileindex);
9165 free(fileindex_path);
9166 if (commit_ref)
9167 got_ref_close(commit_ref);
9168 free(commit_ref_name);
9170 unlockerr = lock_worktree(worktree, LOCK_SH);
9171 if (unlockerr && err == NULL)
9172 err = unlockerr;
9173 return err;
9176 struct check_stage_ok_arg {
9177 struct got_object_id *head_commit_id;
9178 struct got_worktree *worktree;
9179 struct got_fileindex *fileindex;
9180 struct got_repository *repo;
9181 int have_changes;
9184 static const struct got_error *
9185 check_stage_ok(void *arg, unsigned char status,
9186 unsigned char staged_status, const char *relpath,
9187 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
9188 struct got_object_id *commit_id, int dirfd, const char *de_name)
9190 struct check_stage_ok_arg *a = arg;
9191 const struct got_error *err = NULL;
9192 struct got_fileindex_entry *ie;
9193 struct got_object_id base_commit_id;
9194 struct got_object_id *base_commit_idp = NULL;
9195 char *in_repo_path = NULL, *p;
9197 if (status == GOT_STATUS_UNVERSIONED ||
9198 status == GOT_STATUS_NO_CHANGE)
9199 return NULL;
9200 if (status == GOT_STATUS_NONEXISTENT)
9201 return got_error_set_errno(ENOENT, relpath);
9203 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
9204 if (ie == NULL)
9205 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
9207 if (asprintf(&in_repo_path, "%s%s%s", a->worktree->path_prefix,
9208 got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/",
9209 relpath) == -1)
9210 return got_error_from_errno("asprintf");
9212 if (got_fileindex_entry_has_commit(ie)) {
9213 base_commit_idp = got_fileindex_entry_get_commit_id(
9214 &base_commit_id, ie);
9217 if (status == GOT_STATUS_CONFLICT) {
9218 err = got_error_path(ie->path, GOT_ERR_STAGE_CONFLICT);
9219 goto done;
9220 } else if (status != GOT_STATUS_ADD &&
9221 status != GOT_STATUS_MODIFY &&
9222 status != GOT_STATUS_DELETE) {
9223 err = got_error_path(ie->path, GOT_ERR_FILE_STATUS);
9224 goto done;
9227 a->have_changes = 1;
9229 p = in_repo_path;
9230 while (p[0] == '/')
9231 p++;
9232 err = check_out_of_date(p, status, staged_status,
9233 blob_id, base_commit_idp, a->head_commit_id, a->repo,
9234 GOT_ERR_STAGE_OUT_OF_DATE);
9235 done:
9236 free(in_repo_path);
9237 return err;
9240 struct stage_path_arg {
9241 struct got_worktree *worktree;
9242 struct got_fileindex *fileindex;
9243 struct got_repository *repo;
9244 got_worktree_status_cb status_cb;
9245 void *status_arg;
9246 got_worktree_patch_cb patch_cb;
9247 void *patch_arg;
9248 int staged_something;
9249 int allow_bad_symlinks;
9252 static const struct got_error *
9253 stage_path(void *arg, unsigned char status,
9254 unsigned char staged_status, const char *relpath,
9255 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
9256 struct got_object_id *commit_id, int dirfd, const char *de_name)
9258 struct stage_path_arg *a = arg;
9259 const struct got_error *err = NULL;
9260 struct got_fileindex_entry *ie;
9261 char *ondisk_path = NULL, *path_content = NULL;
9262 uint32_t stage;
9263 struct got_object_id *new_staged_blob_id = NULL;
9264 struct stat sb;
9266 if (status == GOT_STATUS_UNVERSIONED)
9267 return NULL;
9269 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
9270 if (ie == NULL)
9271 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
9273 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
9274 relpath)== -1)
9275 return got_error_from_errno("asprintf");
9277 switch (status) {
9278 case GOT_STATUS_ADD:
9279 case GOT_STATUS_MODIFY:
9280 /* XXX could sb.st_mode be passed in by our caller? */
9281 if (lstat(ondisk_path, &sb) == -1) {
9282 err = got_error_from_errno2("lstat", ondisk_path);
9283 break;
9285 if (a->patch_cb) {
9286 if (status == GOT_STATUS_ADD) {
9287 int choice = GOT_PATCH_CHOICE_NONE;
9288 err = (*a->patch_cb)(&choice, a->patch_arg,
9289 status, ie->path, NULL, 1, 1);
9290 if (err)
9291 break;
9292 if (choice != GOT_PATCH_CHOICE_YES)
9293 break;
9294 } else {
9295 int stage_binary_file = 0;
9297 err = create_patched_content(&path_content,
9298 &stage_binary_file, 0,
9299 staged_blob_id ? staged_blob_id : blob_id,
9300 ondisk_path, dirfd, de_name, ie->path,
9301 a->repo, a->patch_cb, a->patch_arg);
9302 if (!stage_binary_file &&
9303 (err || path_content == NULL))
9304 break;
9307 err = got_object_blob_create(&new_staged_blob_id,
9308 path_content ? path_content : ondisk_path, a->repo);
9309 if (err)
9310 break;
9311 memcpy(&ie->staged_blob, new_staged_blob_id,
9312 sizeof(ie->staged_blob));
9313 if (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD)
9314 stage = GOT_FILEIDX_STAGE_ADD;
9315 else
9316 stage = GOT_FILEIDX_STAGE_MODIFY;
9317 got_fileindex_entry_stage_set(ie, stage);
9318 if (S_ISLNK(sb.st_mode)) {
9319 int is_bad_symlink = 0;
9320 if (!a->allow_bad_symlinks) {
9321 char target_path[PATH_MAX];
9322 ssize_t target_len;
9323 target_len = readlink(ondisk_path, target_path,
9324 sizeof(target_path));
9325 if (target_len == -1) {
9326 err = got_error_from_errno2("readlink",
9327 ondisk_path);
9328 break;
9330 err = is_bad_symlink_target(&is_bad_symlink,
9331 target_path, target_len, ondisk_path,
9332 a->worktree->root_path,
9333 a->worktree->meta_dir);
9334 if (err)
9335 break;
9336 if (is_bad_symlink) {
9337 err = got_error_path(ondisk_path,
9338 GOT_ERR_BAD_SYMLINK);
9339 break;
9342 if (is_bad_symlink)
9343 got_fileindex_entry_staged_filetype_set(ie,
9344 GOT_FILEIDX_MODE_BAD_SYMLINK);
9345 else
9346 got_fileindex_entry_staged_filetype_set(ie,
9347 GOT_FILEIDX_MODE_SYMLINK);
9348 } else {
9349 got_fileindex_entry_staged_filetype_set(ie,
9350 GOT_FILEIDX_MODE_REGULAR_FILE);
9352 a->staged_something = 1;
9353 if (a->status_cb == NULL)
9354 break;
9355 err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE,
9356 get_staged_status(ie), relpath, blob_id,
9357 new_staged_blob_id, NULL, dirfd, de_name);
9358 if (err)
9359 break;
9361 * When staging the reverse of the staged diff,
9362 * implicitly unstage the file.
9364 if (got_object_id_cmp(&ie->staged_blob, &ie->blob) == 0) {
9365 got_fileindex_entry_stage_set(ie,
9366 GOT_FILEIDX_STAGE_NONE);
9368 break;
9369 case GOT_STATUS_DELETE:
9370 if (staged_status == GOT_STATUS_DELETE)
9371 break;
9372 if (a->patch_cb) {
9373 int choice = GOT_PATCH_CHOICE_NONE;
9374 err = (*a->patch_cb)(&choice, a->patch_arg, status,
9375 ie->path, NULL, 1, 1);
9376 if (err)
9377 break;
9378 if (choice == GOT_PATCH_CHOICE_NO)
9379 break;
9380 if (choice != GOT_PATCH_CHOICE_YES) {
9381 err = got_error(GOT_ERR_PATCH_CHOICE);
9382 break;
9385 stage = GOT_FILEIDX_STAGE_DELETE;
9386 got_fileindex_entry_stage_set(ie, stage);
9387 a->staged_something = 1;
9388 if (a->status_cb == NULL)
9389 break;
9390 err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE,
9391 get_staged_status(ie), relpath, NULL, NULL, NULL, dirfd,
9392 de_name);
9393 break;
9394 case GOT_STATUS_NO_CHANGE:
9395 break;
9396 case GOT_STATUS_CONFLICT:
9397 err = got_error_path(relpath, GOT_ERR_STAGE_CONFLICT);
9398 break;
9399 case GOT_STATUS_NONEXISTENT:
9400 err = got_error_set_errno(ENOENT, relpath);
9401 break;
9402 default:
9403 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
9404 break;
9407 if (path_content && unlink(path_content) == -1 && err == NULL)
9408 err = got_error_from_errno2("unlink", path_content);
9409 free(path_content);
9410 free(ondisk_path);
9411 free(new_staged_blob_id);
9412 return err;
9415 const struct got_error *
9416 got_worktree_stage(struct got_worktree *worktree,
9417 struct got_pathlist_head *paths,
9418 got_worktree_status_cb status_cb, void *status_arg,
9419 got_worktree_patch_cb patch_cb, void *patch_arg,
9420 int allow_bad_symlinks, struct got_repository *repo)
9422 const struct got_error *err = NULL, *sync_err, *unlockerr;
9423 struct got_pathlist_entry *pe;
9424 struct got_fileindex *fileindex = NULL;
9425 char *fileindex_path = NULL;
9426 struct got_reference *head_ref = NULL;
9427 struct got_object_id *head_commit_id = NULL;
9428 struct check_stage_ok_arg oka;
9429 struct stage_path_arg spa;
9431 err = lock_worktree(worktree, LOCK_EX);
9432 if (err)
9433 return err;
9435 err = got_ref_open(&head_ref, repo,
9436 got_worktree_get_head_ref_name(worktree), 0);
9437 if (err)
9438 goto done;
9439 err = got_ref_resolve(&head_commit_id, repo, head_ref);
9440 if (err)
9441 goto done;
9442 err = open_fileindex(&fileindex, &fileindex_path, worktree,
9443 got_repo_get_object_format(repo));
9444 if (err)
9445 goto done;
9447 /* Check pre-conditions before staging anything. */
9448 oka.head_commit_id = head_commit_id;
9449 oka.worktree = worktree;
9450 oka.fileindex = fileindex;
9451 oka.repo = repo;
9452 oka.have_changes = 0;
9453 TAILQ_FOREACH(pe, paths, entry) {
9454 err = worktree_status(worktree, pe->path, fileindex, repo,
9455 check_stage_ok, &oka, NULL, NULL, 1, 0);
9456 if (err)
9457 goto done;
9459 if (!oka.have_changes) {
9460 err = got_error(GOT_ERR_STAGE_NO_CHANGE);
9461 goto done;
9464 spa.worktree = worktree;
9465 spa.fileindex = fileindex;
9466 spa.repo = repo;
9467 spa.patch_cb = patch_cb;
9468 spa.patch_arg = patch_arg;
9469 spa.status_cb = status_cb;
9470 spa.status_arg = status_arg;
9471 spa.staged_something = 0;
9472 spa.allow_bad_symlinks = allow_bad_symlinks;
9473 TAILQ_FOREACH(pe, paths, entry) {
9474 err = worktree_status(worktree, pe->path, fileindex, repo,
9475 stage_path, &spa, NULL, NULL, 1, 0);
9476 if (err)
9477 goto done;
9479 if (!spa.staged_something) {
9480 err = got_error(GOT_ERR_STAGE_NO_CHANGE);
9481 goto done;
9484 sync_err = sync_fileindex(fileindex, fileindex_path);
9485 if (sync_err && err == NULL)
9486 err = sync_err;
9487 done:
9488 if (head_ref)
9489 got_ref_close(head_ref);
9490 free(head_commit_id);
9491 free(fileindex_path);
9492 if (fileindex)
9493 got_fileindex_free(fileindex);
9494 unlockerr = lock_worktree(worktree, LOCK_SH);
9495 if (unlockerr && err == NULL)
9496 err = unlockerr;
9497 return err;
9500 struct unstage_path_arg {
9501 struct got_worktree *worktree;
9502 struct got_fileindex *fileindex;
9503 struct got_repository *repo;
9504 got_worktree_checkout_cb progress_cb;
9505 void *progress_arg;
9506 got_worktree_patch_cb patch_cb;
9507 void *patch_arg;
9510 static const struct got_error *
9511 create_unstaged_content(char **path_unstaged_content,
9512 char **path_new_staged_content, int *confirm_binary_change,
9513 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
9514 const char *relpath, struct got_repository *repo,
9515 got_worktree_patch_cb patch_cb, void *patch_arg)
9517 const struct got_error *err, *free_err;
9518 struct got_blob_object *blob = NULL, *staged_blob = NULL;
9519 FILE *f1 = NULL, *f2 = NULL, *outfile = NULL, *rejectfile = NULL;
9520 char *path1 = NULL, *path2 = NULL, *label1 = NULL;
9521 struct got_diffreg_result *diffreg_result = NULL;
9522 int choice, line_cur1 = 1, line_cur2 = 1, n = 0, nchunks_used = 0;
9523 int have_content = 0, have_rejected_content = 0, i = 0, nchanges = 0;
9524 int fd1 = -1, fd2 = -1;
9526 *confirm_binary_change = 0;
9527 *path_unstaged_content = NULL;
9528 *path_new_staged_content = NULL;
9530 err = got_object_id_str(&label1, blob_id);
9531 if (err)
9532 return err;
9534 fd1 = got_opentempfd();
9535 if (fd1 == -1) {
9536 err = got_error_from_errno("got_opentempfd");
9537 goto done;
9539 fd2 = got_opentempfd();
9540 if (fd2 == -1) {
9541 err = got_error_from_errno("got_opentempfd");
9542 goto done;
9545 err = got_object_open_as_blob(&blob, repo, blob_id, 8192, fd1);
9546 if (err)
9547 goto done;
9549 err = got_opentemp_named(&path1, &f1, "got-unstage-blob-base", "");
9550 if (err)
9551 goto done;
9553 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob);
9554 if (err)
9555 goto done;
9557 err = got_object_open_as_blob(&staged_blob, repo, staged_blob_id, 8192,
9558 fd2);
9559 if (err)
9560 goto done;
9562 err = got_opentemp_named(&path2, &f2, "got-unstage-blob-staged", "");
9563 if (err)
9564 goto done;
9566 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f2, staged_blob);
9567 if (err)
9568 goto done;
9570 err = got_diff_files(&diffreg_result, f1, 1, label1, f2, 1,
9571 path2, 3, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS);
9572 if (err)
9573 goto done;
9575 if (diff_result_has_binary(diffreg_result->result)) {
9576 err = accept_or_reject_binary_change(&choice, relpath,
9577 patch_cb, patch_arg);
9578 if (err == NULL && choice == GOT_PATCH_CHOICE_YES)
9579 *confirm_binary_change = 1;
9580 goto done;
9583 err = got_opentemp_named(path_unstaged_content, &outfile,
9584 "got-unstaged-content", "");
9585 if (err)
9586 goto done;
9587 err = got_opentemp_named(path_new_staged_content, &rejectfile,
9588 "got-new-staged-content", "");
9589 if (err)
9590 goto done;
9592 if (fseek(f1, 0L, SEEK_SET) == -1) {
9593 err = got_ferror(f1, GOT_ERR_IO);
9594 goto done;
9596 if (fseek(f2, 0L, SEEK_SET) == -1) {
9597 err = got_ferror(f2, GOT_ERR_IO);
9598 goto done;
9600 /* Count the number of actual changes in the diff result. */
9601 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
9602 struct diff_chunk_context cc = {};
9603 diff_chunk_context_load_change(&cc, &nchunks_used,
9604 diffreg_result->result, n, 0);
9605 nchanges++;
9607 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
9608 err = apply_or_reject_change(&choice, &nchunks_used,
9609 diffreg_result->result, n, relpath, f1, f2,
9610 &line_cur1, &line_cur2,
9611 outfile, rejectfile, ++i, nchanges, patch_cb, patch_arg);
9612 if (err)
9613 goto done;
9614 if (choice == GOT_PATCH_CHOICE_YES)
9615 have_content = 1;
9616 else
9617 have_rejected_content = 1;
9618 if (choice == GOT_PATCH_CHOICE_QUIT)
9619 break;
9621 if (have_content || have_rejected_content)
9622 err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2,
9623 outfile, rejectfile);
9624 done:
9625 free(label1);
9626 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
9627 err = got_error_from_errno("close");
9628 if (blob)
9629 got_object_blob_close(blob);
9630 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
9631 err = got_error_from_errno("close");
9632 if (staged_blob)
9633 got_object_blob_close(staged_blob);
9634 free_err = got_diffreg_result_free(diffreg_result);
9635 if (free_err && err == NULL)
9636 err = free_err;
9637 if (f1 && fclose(f1) == EOF && err == NULL)
9638 err = got_error_from_errno2("fclose", path1);
9639 if (f2 && fclose(f2) == EOF && err == NULL)
9640 err = got_error_from_errno2("fclose", path2);
9641 if (outfile && fclose(outfile) == EOF && err == NULL)
9642 err = got_error_from_errno2("fclose", *path_unstaged_content);
9643 if (rejectfile && fclose(rejectfile) == EOF && err == NULL)
9644 err = got_error_from_errno2("fclose", *path_new_staged_content);
9645 if (path1 && unlink(path1) == -1 && err == NULL)
9646 err = got_error_from_errno2("unlink", path1);
9647 if (path2 && unlink(path2) == -1 && err == NULL)
9648 err = got_error_from_errno2("unlink", path2);
9649 if (err || !have_content) {
9650 if (*path_unstaged_content &&
9651 unlink(*path_unstaged_content) == -1 && err == NULL)
9652 err = got_error_from_errno2("unlink",
9653 *path_unstaged_content);
9654 free(*path_unstaged_content);
9655 *path_unstaged_content = NULL;
9657 if (err || !have_content || !have_rejected_content) {
9658 if (*path_new_staged_content &&
9659 unlink(*path_new_staged_content) == -1 && err == NULL)
9660 err = got_error_from_errno2("unlink",
9661 *path_new_staged_content);
9662 free(*path_new_staged_content);
9663 *path_new_staged_content = NULL;
9665 free(path1);
9666 free(path2);
9667 return err;
9670 static const struct got_error *
9671 unstage_hunks(int *confirm_binary_change, struct got_object_id *staged_blob_id,
9672 struct got_blob_object *blob_base, struct got_object_id *blob_id,
9673 struct got_fileindex_entry *ie, const char *ondisk_path,
9674 const char *label_orig, struct got_worktree *worktree,
9675 struct got_repository *repo,
9676 got_worktree_patch_cb patch_cb, void *patch_arg,
9677 got_worktree_checkout_cb progress_cb, void *progress_arg)
9679 const struct got_error *err = NULL;
9680 char *path_unstaged_content = NULL;
9681 char *path_new_staged_content = NULL;
9682 char *parent = NULL, *base_path = NULL;
9683 char *blob_base_path = NULL;
9684 struct got_object_id *new_staged_blob_id = NULL;
9685 FILE *f = NULL, *f_base = NULL, *f_deriv2 = NULL;
9686 struct stat sb;
9688 err = create_unstaged_content(&path_unstaged_content,
9689 &path_new_staged_content, confirm_binary_change,
9690 blob_id, staged_blob_id, ie->path, repo, patch_cb, patch_arg);
9691 if (err)
9692 return err;
9694 if (path_unstaged_content == NULL)
9695 return NULL;
9697 if (path_new_staged_content) {
9698 err = got_object_blob_create(&new_staged_blob_id,
9699 path_new_staged_content, repo);
9700 if (err)
9701 goto done;
9704 f = fopen(path_unstaged_content, "re");
9705 if (f == NULL) {
9706 err = got_error_from_errno2("fopen",
9707 path_unstaged_content);
9708 goto done;
9710 if (fstat(fileno(f), &sb) == -1) {
9711 err = got_error_from_errno2("fstat", path_unstaged_content);
9712 goto done;
9714 if (got_fileindex_entry_staged_filetype_get(ie) ==
9715 GOT_FILEIDX_MODE_SYMLINK && sb.st_size < PATH_MAX) {
9716 char link_target[PATH_MAX];
9717 size_t r;
9718 r = fread(link_target, 1, sizeof(link_target), f);
9719 if (r == 0 && ferror(f)) {
9720 err = got_error_from_errno("fread");
9721 goto done;
9723 if (r >= sizeof(link_target)) { /* should not happen */
9724 err = got_error(GOT_ERR_NO_SPACE);
9725 goto done;
9727 link_target[r] = '\0';
9728 err = merge_symlink(worktree, blob_base,
9729 ondisk_path, ie->path, label_orig, link_target,
9730 worktree->base_commit_id, repo, progress_cb,
9731 progress_arg);
9732 } else {
9733 int local_changes_subsumed;
9735 err = got_path_dirname(&parent, ondisk_path);
9736 if (err)
9737 return err;
9739 if (asprintf(&base_path, "%s/got-unstage-blob-orig",
9740 parent) == -1) {
9741 err = got_error_from_errno("asprintf");
9742 base_path = NULL;
9743 goto done;
9746 err = got_opentemp_named(&blob_base_path, &f_base,
9747 base_path, "");
9748 if (err)
9749 goto done;
9750 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_base,
9751 blob_base);
9752 if (err)
9753 goto done;
9756 * In order the run a 3-way merge with a symlink we copy the symlink's
9757 * target path into a temporary file and use that file with diff3.
9759 if (S_ISLNK(got_fileindex_perms_to_st(ie))) {
9760 err = dump_symlink_target_path_to_file(&f_deriv2,
9761 ondisk_path);
9762 if (err)
9763 goto done;
9764 } else {
9765 int fd;
9766 fd = open(ondisk_path,
9767 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
9768 if (fd == -1) {
9769 err = got_error_from_errno2("open", ondisk_path);
9770 goto done;
9772 f_deriv2 = fdopen(fd, "r");
9773 if (f_deriv2 == NULL) {
9774 err = got_error_from_errno2("fdopen", ondisk_path);
9775 close(fd);
9776 goto done;
9780 err = merge_file(&local_changes_subsumed, worktree,
9781 f_base, f, f_deriv2, ondisk_path, ie->path,
9782 got_fileindex_perms_to_st(ie),
9783 label_orig, "unstaged", NULL, GOT_DIFF_ALGORITHM_MYERS,
9784 repo, progress_cb, progress_arg);
9786 if (err)
9787 goto done;
9789 if (new_staged_blob_id) {
9790 memcpy(&ie->staged_blob, new_staged_blob_id,
9791 sizeof(ie->staged_blob));
9792 } else {
9793 got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
9794 got_fileindex_entry_staged_filetype_set(ie, 0);
9796 done:
9797 free(new_staged_blob_id);
9798 if (path_unstaged_content &&
9799 unlink(path_unstaged_content) == -1 && err == NULL)
9800 err = got_error_from_errno2("unlink", path_unstaged_content);
9801 if (path_new_staged_content &&
9802 unlink(path_new_staged_content) == -1 && err == NULL)
9803 err = got_error_from_errno2("unlink", path_new_staged_content);
9804 if (blob_base_path && unlink(blob_base_path) == -1 && err == NULL)
9805 err = got_error_from_errno2("unlink", blob_base_path);
9806 if (f_base && fclose(f_base) == EOF && err == NULL)
9807 err = got_error_from_errno2("fclose", path_unstaged_content);
9808 if (f && fclose(f) == EOF && err == NULL)
9809 err = got_error_from_errno2("fclose", path_unstaged_content);
9810 if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL)
9811 err = got_error_from_errno2("fclose", ondisk_path);
9812 free(path_unstaged_content);
9813 free(path_new_staged_content);
9814 free(blob_base_path);
9815 free(parent);
9816 free(base_path);
9817 return err;
9820 static const struct got_error *
9821 unstage_path(void *arg, unsigned char status,
9822 unsigned char staged_status, const char *relpath,
9823 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
9824 struct got_object_id *commit_id, int dirfd, const char *de_name)
9826 const struct got_error *err = NULL;
9827 struct unstage_path_arg *a = arg;
9828 struct got_fileindex_entry *ie;
9829 struct got_blob_object *blob_base = NULL, *blob_staged = NULL;
9830 char *ondisk_path = NULL;
9831 char *id_str = NULL, *label_orig = NULL;
9832 int local_changes_subsumed;
9833 struct stat sb;
9834 int fd1 = -1, fd2 = -1;
9836 if (staged_status != GOT_STATUS_ADD &&
9837 staged_status != GOT_STATUS_MODIFY &&
9838 staged_status != GOT_STATUS_DELETE)
9839 return NULL;
9841 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
9842 if (ie == NULL)
9843 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
9845 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, relpath)
9846 == -1)
9847 return got_error_from_errno("asprintf");
9849 err = got_object_id_str(&id_str,
9850 commit_id ? commit_id : a->worktree->base_commit_id);
9851 if (err)
9852 goto done;
9853 if (asprintf(&label_orig, "%s: commit %s", GOT_MERGE_LABEL_BASE,
9854 id_str) == -1) {
9855 err = got_error_from_errno("asprintf");
9856 goto done;
9859 fd1 = got_opentempfd();
9860 if (fd1 == -1) {
9861 err = got_error_from_errno("got_opentempfd");
9862 goto done;
9864 fd2 = got_opentempfd();
9865 if (fd2 == -1) {
9866 err = got_error_from_errno("got_opentempfd");
9867 goto done;
9870 switch (staged_status) {
9871 case GOT_STATUS_MODIFY:
9872 err = got_object_open_as_blob(&blob_base, a->repo,
9873 blob_id, 8192, fd1);
9874 if (err)
9875 break;
9876 /* fall through */
9877 case GOT_STATUS_ADD:
9878 if (status == GOT_STATUS_MISSING) {
9879 /* Cannot merge changes into missing files. */
9880 err = (*a->progress_cb)(a->progress_arg, status,
9881 relpath);
9882 goto done;
9884 if (a->patch_cb) {
9885 if (staged_status == GOT_STATUS_ADD) {
9886 int choice = GOT_PATCH_CHOICE_NONE;
9887 err = (*a->patch_cb)(&choice, a->patch_arg,
9888 staged_status, ie->path, NULL, 1, 1);
9889 if (err)
9890 break;
9891 if (choice != GOT_PATCH_CHOICE_YES)
9892 break;
9893 } else {
9894 int unstage_binary_file = 0;
9896 err = unstage_hunks(&unstage_binary_file,
9897 staged_blob_id, blob_base, blob_id,
9898 ie, ondisk_path, label_orig,
9899 a->worktree, a->repo,
9900 a->patch_cb, a->patch_arg,
9901 a->progress_cb, a->progress_arg);
9902 if (!unstage_binary_file)
9903 break; /* Done with this file. */
9906 err = got_object_open_as_blob(&blob_staged, a->repo,
9907 staged_blob_id, 8192, fd2);
9908 if (err)
9909 break;
9910 switch (got_fileindex_entry_staged_filetype_get(ie)) {
9911 case GOT_FILEIDX_MODE_BAD_SYMLINK:
9912 case GOT_FILEIDX_MODE_REGULAR_FILE:
9913 err = merge_blob(&local_changes_subsumed, a->worktree,
9914 blob_base, ondisk_path, relpath,
9915 got_fileindex_perms_to_st(ie), label_orig,
9916 blob_staged, commit_id ? commit_id :
9917 a->worktree->base_commit_id, a->repo,
9918 a->progress_cb, a->progress_arg);
9919 break;
9920 case GOT_FILEIDX_MODE_SYMLINK:
9921 if (S_ISLNK(got_fileindex_perms_to_st(ie))) {
9922 char *staged_target;
9923 err = got_object_blob_read_to_str(
9924 &staged_target, blob_staged);
9925 if (err)
9926 goto done;
9927 err = merge_symlink(a->worktree, blob_base,
9928 ondisk_path, relpath, label_orig,
9929 staged_target, commit_id ? commit_id :
9930 a->worktree->base_commit_id,
9931 a->repo, a->progress_cb, a->progress_arg);
9932 free(staged_target);
9933 } else {
9934 err = merge_blob(&local_changes_subsumed,
9935 a->worktree, blob_base, ondisk_path,
9936 relpath, got_fileindex_perms_to_st(ie),
9937 label_orig, blob_staged,
9938 commit_id ? commit_id :
9939 a->worktree->base_commit_id, a->repo,
9940 a->progress_cb, a->progress_arg);
9942 break;
9943 default:
9944 err = got_error_path(relpath, GOT_ERR_BAD_FILETYPE);
9945 break;
9947 if (err == NULL) {
9948 got_fileindex_entry_stage_set(ie,
9949 GOT_FILEIDX_STAGE_NONE);
9950 got_fileindex_entry_staged_filetype_set(ie, 0);
9952 break;
9953 case GOT_STATUS_DELETE:
9954 if (a->patch_cb) {
9955 int choice = GOT_PATCH_CHOICE_NONE;
9956 err = (*a->patch_cb)(&choice, a->patch_arg,
9957 staged_status, ie->path, NULL, 1, 1);
9958 if (err)
9959 break;
9960 if (choice == GOT_PATCH_CHOICE_NO)
9961 break;
9962 if (choice != GOT_PATCH_CHOICE_YES) {
9963 err = got_error(GOT_ERR_PATCH_CHOICE);
9964 break;
9967 got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
9968 got_fileindex_entry_staged_filetype_set(ie, 0);
9969 err = get_file_status(&status, &sb, ie, ondisk_path,
9970 dirfd, de_name, a->repo);
9971 if (err)
9972 break;
9973 err = (*a->progress_cb)(a->progress_arg, status, relpath);
9974 break;
9976 done:
9977 free(ondisk_path);
9978 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
9979 err = got_error_from_errno("close");
9980 if (blob_base)
9981 got_object_blob_close(blob_base);
9982 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
9983 err = got_error_from_errno("close");
9984 if (blob_staged)
9985 got_object_blob_close(blob_staged);
9986 free(id_str);
9987 free(label_orig);
9988 return err;
9991 const struct got_error *
9992 got_worktree_unstage(struct got_worktree *worktree,
9993 struct got_pathlist_head *paths,
9994 got_worktree_checkout_cb progress_cb, void *progress_arg,
9995 got_worktree_patch_cb patch_cb, void *patch_arg,
9996 struct got_repository *repo)
9998 const struct got_error *err = NULL, *sync_err, *unlockerr;
9999 struct got_pathlist_entry *pe;
10000 struct got_fileindex *fileindex = NULL;
10001 char *fileindex_path = NULL;
10002 struct unstage_path_arg upa;
10004 err = lock_worktree(worktree, LOCK_EX);
10005 if (err)
10006 return err;
10008 err = open_fileindex(&fileindex, &fileindex_path, worktree,
10009 got_repo_get_object_format(repo));
10010 if (err)
10011 goto done;
10013 upa.worktree = worktree;
10014 upa.fileindex = fileindex;
10015 upa.repo = repo;
10016 upa.progress_cb = progress_cb;
10017 upa.progress_arg = progress_arg;
10018 upa.patch_cb = patch_cb;
10019 upa.patch_arg = patch_arg;
10020 TAILQ_FOREACH(pe, paths, entry) {
10021 err = worktree_status(worktree, pe->path, fileindex, repo,
10022 unstage_path, &upa, NULL, NULL, 1, 0);
10023 if (err)
10024 goto done;
10027 sync_err = sync_fileindex(fileindex, fileindex_path);
10028 if (sync_err && err == NULL)
10029 err = sync_err;
10030 done:
10031 free(fileindex_path);
10032 if (fileindex)
10033 got_fileindex_free(fileindex);
10034 unlockerr = lock_worktree(worktree, LOCK_SH);
10035 if (unlockerr && err == NULL)
10036 err = unlockerr;
10037 return err;
10040 struct report_file_info_arg {
10041 struct got_worktree *worktree;
10042 got_worktree_path_info_cb info_cb;
10043 void *info_arg;
10044 struct got_pathlist_head *paths;
10045 got_cancel_cb cancel_cb;
10046 void *cancel_arg;
10049 static const struct got_error *
10050 report_file_info(void *arg, struct got_fileindex_entry *ie)
10052 const struct got_error *err;
10053 struct report_file_info_arg *a = arg;
10054 struct got_pathlist_entry *pe;
10055 struct got_object_id blob_id, staged_blob_id, commit_id;
10056 struct got_object_id *blob_idp = NULL, *staged_blob_idp = NULL;
10057 struct got_object_id *commit_idp = NULL;
10058 int stage;
10060 if (a->cancel_cb) {
10061 err = a->cancel_cb(a->cancel_arg);
10062 if (err)
10063 return err;
10066 TAILQ_FOREACH(pe, a->paths, entry) {
10067 if (pe->path_len == 0 || strcmp(pe->path, ie->path) == 0 ||
10068 got_path_is_child(ie->path, pe->path, pe->path_len))
10069 break;
10071 if (pe == NULL) /* not found */
10072 return NULL;
10074 if (got_fileindex_entry_has_blob(ie))
10075 blob_idp = got_fileindex_entry_get_blob_id(&blob_id, ie);
10076 stage = got_fileindex_entry_stage_get(ie);
10077 if (stage == GOT_FILEIDX_STAGE_MODIFY ||
10078 stage == GOT_FILEIDX_STAGE_ADD) {
10079 staged_blob_idp = got_fileindex_entry_get_staged_blob_id(
10080 &staged_blob_id, ie);
10083 if (got_fileindex_entry_has_commit(ie))
10084 commit_idp = got_fileindex_entry_get_commit_id(&commit_id, ie);
10086 return a->info_cb(a->info_arg, ie->path, got_fileindex_perms_to_st(ie),
10087 (time_t)ie->mtime_sec, blob_idp, staged_blob_idp, commit_idp);
10090 const struct got_error *
10091 got_worktree_path_info_prepare(struct got_fileindex **fileindex,
10092 struct got_worktree *worktree, struct got_repository *repo)
10094 const struct got_error *err;
10095 char *fileindex_path;
10097 err = lock_worktree(worktree, LOCK_SH);
10098 if (err)
10099 return err;
10101 err = open_fileindex(fileindex, &fileindex_path, worktree,
10102 got_repo_get_object_format(repo));
10103 free(fileindex_path);
10104 return err;
10107 uint32_t
10108 got_worktree_get_fileindex_version(struct got_fileindex *fileindex)
10110 return got_fileindex_get_version(fileindex);
10113 const struct got_error *
10114 got_worktree_path_info(struct got_worktree *worktree,
10115 struct got_fileindex *fileindex,
10116 struct got_pathlist_head *paths,
10117 got_worktree_path_info_cb info_cb, void *info_arg,
10118 got_cancel_cb cancel_cb, void *cancel_arg)
10121 struct report_file_info_arg arg;
10123 arg.worktree = worktree;
10124 arg.info_cb = info_cb;
10125 arg.info_arg = info_arg;
10126 arg.paths = paths;
10127 arg.cancel_cb = cancel_cb;
10128 arg.cancel_arg = cancel_arg;
10129 return got_fileindex_for_each_entry_safe(fileindex, report_file_info,
10130 &arg);
10133 const struct got_error *
10134 got_worktree_path_info_complete(struct got_fileindex *fileindex,
10135 struct got_worktree *worktree)
10137 if (fileindex)
10138 got_fileindex_free(fileindex);
10139 return lock_worktree(worktree, LOCK_UN);
10142 static const struct got_error *
10143 patch_check_path(const char *p, char **path, unsigned char *status,
10144 unsigned char *staged_status, struct got_fileindex *fileindex,
10145 struct got_worktree *worktree, struct got_repository *repo)
10147 const struct got_error *err;
10148 struct got_fileindex_entry *ie;
10149 struct stat sb;
10150 char *ondisk_path = NULL;
10152 err = got_worktree_resolve_path(path, worktree, p);
10153 if (err)
10154 return err;
10156 if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path,
10157 *path[0] ? "/" : "", *path) == -1)
10158 return got_error_from_errno("asprintf");
10160 ie = got_fileindex_entry_get(fileindex, *path, strlen(*path));
10161 if (ie) {
10162 *staged_status = get_staged_status(ie);
10163 err = get_file_status(status, &sb, ie, ondisk_path, -1, NULL,
10164 repo);
10165 if (err)
10166 goto done;
10167 } else {
10168 *staged_status = GOT_STATUS_NO_CHANGE;
10169 *status = GOT_STATUS_UNVERSIONED;
10170 if (lstat(ondisk_path, &sb) == -1) {
10171 if (errno != ENOENT) {
10172 err = got_error_from_errno2("lstat",
10173 ondisk_path);
10174 goto done;
10176 *status = GOT_STATUS_NONEXISTENT;
10180 done:
10181 free(ondisk_path);
10182 return err;
10185 static const struct got_error *
10186 patch_can_rm(const char *path, unsigned char status,
10187 unsigned char staged_status)
10189 if (status == GOT_STATUS_NONEXISTENT)
10190 return got_error_set_errno(ENOENT, path);
10191 if (status != GOT_STATUS_NO_CHANGE &&
10192 status != GOT_STATUS_ADD &&
10193 status != GOT_STATUS_MODIFY &&
10194 status != GOT_STATUS_MODE_CHANGE)
10195 return got_error_path(path, GOT_ERR_FILE_STATUS);
10196 if (staged_status == GOT_STATUS_DELETE)
10197 return got_error_path(path, GOT_ERR_FILE_STATUS);
10198 return NULL;
10201 static const struct got_error *
10202 patch_can_add(const char *path, unsigned char status)
10204 if (status != GOT_STATUS_NONEXISTENT)
10205 return got_error_path(path, GOT_ERR_FILE_STATUS);
10206 return NULL;
10209 static const struct got_error *
10210 patch_can_edit(const char *path, unsigned char status,
10211 unsigned char staged_status)
10213 if (status == GOT_STATUS_NONEXISTENT)
10214 return got_error_set_errno(ENOENT, path);
10215 if (status != GOT_STATUS_NO_CHANGE &&
10216 status != GOT_STATUS_ADD &&
10217 status != GOT_STATUS_MODIFY)
10218 return got_error_path(path, GOT_ERR_FILE_STATUS);
10219 if (staged_status == GOT_STATUS_DELETE)
10220 return got_error_path(path, GOT_ERR_FILE_STATUS);
10221 return NULL;
10224 const struct got_error *
10225 got_worktree_patch_prepare(struct got_fileindex **fileindex,
10226 char **fileindex_path, struct got_worktree *worktree,
10227 struct got_repository *repo)
10229 const struct got_error *err;
10231 err = lock_worktree(worktree, LOCK_EX);
10232 if (err)
10233 return err;
10235 return open_fileindex(fileindex, fileindex_path, worktree,
10236 got_repo_get_object_format(repo));
10239 const struct got_error *
10240 got_worktree_patch_check_path(const char *old, const char *new,
10241 char **oldpath, char **newpath, struct got_worktree *worktree,
10242 struct got_repository *repo, struct got_fileindex *fileindex)
10244 const struct got_error *err = NULL;
10245 int file_renamed = 0;
10246 unsigned char status_old, staged_status_old;
10247 unsigned char status_new, staged_status_new;
10249 *oldpath = NULL;
10250 *newpath = NULL;
10252 err = patch_check_path(old != NULL ? old : new, oldpath,
10253 &status_old, &staged_status_old, fileindex, worktree, repo);
10254 if (err)
10255 goto done;
10257 err = patch_check_path(new != NULL ? new : old, newpath,
10258 &status_new, &staged_status_new, fileindex, worktree, repo);
10259 if (err)
10260 goto done;
10262 if (old != NULL && new != NULL && strcmp(old, new) != 0)
10263 file_renamed = 1;
10265 if (old != NULL && new == NULL)
10266 err = patch_can_rm(*oldpath, status_old, staged_status_old);
10267 else if (file_renamed) {
10268 err = patch_can_rm(*oldpath, status_old, staged_status_old);
10269 if (err == NULL)
10270 err = patch_can_add(*newpath, status_new);
10271 } else if (old == NULL)
10272 err = patch_can_add(*newpath, status_new);
10273 else
10274 err = patch_can_edit(*newpath, status_new, staged_status_new);
10276 done:
10277 if (err) {
10278 free(*oldpath);
10279 *oldpath = NULL;
10280 free(*newpath);
10281 *newpath = NULL;
10283 return err;
10286 const struct got_error *
10287 got_worktree_patch_schedule_add(const char *path, struct got_repository *repo,
10288 struct got_worktree *worktree, struct got_fileindex *fileindex,
10289 got_worktree_checkout_cb progress_cb, void *progress_arg)
10291 struct schedule_addition_args saa;
10293 memset(&saa, 0, sizeof(saa));
10294 saa.worktree = worktree;
10295 saa.fileindex = fileindex;
10296 saa.progress_cb = progress_cb;
10297 saa.progress_arg = progress_arg;
10298 saa.repo = repo;
10300 return worktree_status(worktree, path, fileindex, repo,
10301 schedule_addition, &saa, NULL, NULL, 1, 0);
10304 const struct got_error *
10305 got_worktree_patch_schedule_rm(const char *path, struct got_repository *repo,
10306 struct got_worktree *worktree, struct got_fileindex *fileindex,
10307 got_worktree_delete_cb progress_cb, void *progress_arg)
10309 const struct got_error *err;
10310 struct schedule_deletion_args sda;
10311 char *ondisk_status_path;
10313 memset(&sda, 0, sizeof(sda));
10314 sda.worktree = worktree;
10315 sda.fileindex = fileindex;
10316 sda.progress_cb = progress_cb;
10317 sda.progress_arg = progress_arg;
10318 sda.repo = repo;
10319 sda.delete_local_mods = 0;
10320 sda.keep_on_disk = 0;
10321 sda.ignore_missing_paths = 0;
10322 sda.status_codes = NULL;
10323 if (asprintf(&ondisk_status_path, "%s/%s",
10324 got_worktree_get_root_path(worktree), path) == -1)
10325 return got_error_from_errno("asprintf");
10326 sda.status_path = ondisk_status_path;
10327 sda.status_path_len = strlen(ondisk_status_path);
10329 err = worktree_status(worktree, path, fileindex, repo,
10330 schedule_for_deletion, &sda, NULL, NULL, 1, 1);
10331 free(ondisk_status_path);
10332 return err;
10335 const struct got_error *
10336 got_worktree_patch_complete(struct got_worktree *worktree,
10337 struct got_fileindex *fileindex,
10338 const char *fileindex_path)
10340 const struct got_error *err = NULL, *unlock_err;
10342 if (fileindex) {
10343 err = sync_fileindex(fileindex, fileindex_path);
10344 got_fileindex_free(fileindex);
10347 unlock_err = lock_worktree(worktree, LOCK_UN);
10348 if (unlock_err && err == NULL)
10349 err = unlock_err;
10351 return err;