Blob


1 /*
2 * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <sys/stat.h>
18 #include <sys/queue.h>
19 #include <sys/tree.h>
21 #include <dirent.h>
22 #include <limits.h>
23 #include <stddef.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <sha1.h>
32 #include <zlib.h>
33 #include <fnmatch.h>
34 #include <libgen.h>
35 #include <uuid.h>
36 #include <util.h>
38 #include "got_error.h"
39 #include "got_repository.h"
40 #include "got_reference.h"
41 #include "got_object.h"
42 #include "got_path.h"
43 #include "got_cancel.h"
44 #include "got_worktree.h"
45 #include "got_opentemp.h"
46 #include "got_diff.h"
48 #include "got_lib_worktree.h"
49 #include "got_lib_sha1.h"
50 #include "got_lib_fileindex.h"
51 #include "got_lib_inflate.h"
52 #include "got_lib_delta.h"
53 #include "got_lib_object.h"
54 #include "got_lib_object_parse.h"
55 #include "got_lib_object_create.h"
56 #include "got_lib_object_idset.h"
57 #include "got_lib_diff.h"
58 #include "got_lib_gotconfig.h"
60 #ifndef MIN
61 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
62 #endif
64 #define GOT_MERGE_LABEL_MERGED "merged change"
65 #define GOT_MERGE_LABEL_BASE "3-way merge base"
67 static mode_t apply_umask(mode_t);
69 static const struct got_error *
70 create_meta_file(const char *path_got, const char *name, const char *content)
71 {
72 const struct got_error *err = NULL;
73 char *path;
75 if (asprintf(&path, "%s/%s", path_got, name) == -1)
76 return got_error_from_errno("asprintf");
78 err = got_path_create_file(path, content);
79 free(path);
80 return err;
81 }
83 static const struct got_error *
84 update_meta_file(const char *path_got, const char *name, const char *content)
85 {
86 const struct got_error *err = NULL;
87 FILE *tmpfile = NULL;
88 char *tmppath = NULL;
89 char *path = NULL;
91 if (asprintf(&path, "%s/%s", path_got, name) == -1) {
92 err = got_error_from_errno("asprintf");
93 path = NULL;
94 goto done;
95 }
97 err = got_opentemp_named(&tmppath, &tmpfile, path, "");
98 if (err)
99 goto done;
101 if (content) {
102 int len = fprintf(tmpfile, "%s\n", content);
103 if (len != strlen(content) + 1) {
104 err = got_error_from_errno2("fprintf", tmppath);
105 goto done;
109 if (rename(tmppath, path) != 0) {
110 err = got_error_from_errno3("rename", tmppath, path);
111 unlink(tmppath);
112 goto done;
115 done:
116 if (fclose(tmpfile) == EOF && err == NULL)
117 err = got_error_from_errno2("fclose", tmppath);
118 free(tmppath);
119 return err;
122 static const struct got_error *
123 write_head_ref(const char *path_got, struct got_reference *head_ref)
125 const struct got_error *err = NULL;
126 char *refstr = NULL;
128 if (got_ref_is_symbolic(head_ref)) {
129 refstr = got_ref_to_str(head_ref);
130 if (refstr == NULL)
131 return got_error_from_errno("got_ref_to_str");
132 } else {
133 refstr = strdup(got_ref_get_name(head_ref));
134 if (refstr == NULL)
135 return got_error_from_errno("strdup");
137 err = update_meta_file(path_got, GOT_WORKTREE_HEAD_REF, refstr);
138 free(refstr);
139 return err;
142 const struct got_error *
143 got_worktree_init(const char *path, struct got_reference *head_ref,
144 const char *prefix, struct got_repository *repo)
146 const struct got_error *err = NULL;
147 struct got_object_id *commit_id = NULL;
148 uuid_t uuid;
149 uint32_t uuid_status;
150 int obj_type;
151 char *path_got = NULL;
152 char *formatstr = NULL;
153 char *absprefix = NULL;
154 char *basestr = NULL;
155 char *uuidstr = NULL;
157 if (strcmp(path, got_repo_get_path(repo)) == 0) {
158 err = got_error(GOT_ERR_WORKTREE_REPO);
159 goto done;
162 err = got_ref_resolve(&commit_id, repo, head_ref);
163 if (err)
164 return err;
165 err = got_object_get_type(&obj_type, repo, commit_id);
166 if (err)
167 return err;
168 if (obj_type != GOT_OBJ_TYPE_COMMIT)
169 return got_error(GOT_ERR_OBJ_TYPE);
171 if (!got_path_is_absolute(prefix)) {
172 if (asprintf(&absprefix, "/%s", prefix) == -1)
173 return got_error_from_errno("asprintf");
176 /* Create top-level directory (may already exist). */
177 if (mkdir(path, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
178 err = got_error_from_errno2("mkdir", path);
179 goto done;
182 /* Create .got directory (may already exist). */
183 if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) {
184 err = got_error_from_errno("asprintf");
185 goto done;
187 if (mkdir(path_got, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
188 err = got_error_from_errno2("mkdir", path_got);
189 goto done;
192 /* Create an empty lock file. */
193 err = create_meta_file(path_got, GOT_WORKTREE_LOCK, NULL);
194 if (err)
195 goto done;
197 /* Create an empty file index. */
198 err = create_meta_file(path_got, GOT_WORKTREE_FILE_INDEX, NULL);
199 if (err)
200 goto done;
202 /* Write the HEAD reference. */
203 err = write_head_ref(path_got, head_ref);
204 if (err)
205 goto done;
207 /* Record our base commit. */
208 err = got_object_id_str(&basestr, commit_id);
209 if (err)
210 goto done;
211 err = create_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, basestr);
212 if (err)
213 goto done;
215 /* Store path to repository. */
216 err = create_meta_file(path_got, GOT_WORKTREE_REPOSITORY,
217 got_repo_get_path(repo));
218 if (err)
219 goto done;
221 /* Store in-repository path prefix. */
222 err = create_meta_file(path_got, GOT_WORKTREE_PATH_PREFIX,
223 absprefix ? absprefix : prefix);
224 if (err)
225 goto done;
227 /* Generate UUID. */
228 uuid_create(&uuid, &uuid_status);
229 if (uuid_status != uuid_s_ok) {
230 err = got_error_uuid(uuid_status, "uuid_create");
231 goto done;
233 uuid_to_string(&uuid, &uuidstr, &uuid_status);
234 if (uuid_status != uuid_s_ok) {
235 err = got_error_uuid(uuid_status, "uuid_to_string");
236 goto done;
238 err = create_meta_file(path_got, GOT_WORKTREE_UUID, uuidstr);
239 if (err)
240 goto done;
242 /* Stamp work tree with format file. */
243 if (asprintf(&formatstr, "%d", GOT_WORKTREE_FORMAT_VERSION) == -1) {
244 err = got_error_from_errno("asprintf");
245 goto done;
247 err = create_meta_file(path_got, GOT_WORKTREE_FORMAT, formatstr);
248 if (err)
249 goto done;
251 done:
252 free(commit_id);
253 free(path_got);
254 free(formatstr);
255 free(absprefix);
256 free(basestr);
257 free(uuidstr);
258 return err;
261 const struct got_error *
262 got_worktree_match_path_prefix(int *match, struct got_worktree *worktree,
263 const char *path_prefix)
265 char *absprefix = NULL;
267 if (!got_path_is_absolute(path_prefix)) {
268 if (asprintf(&absprefix, "/%s", path_prefix) == -1)
269 return got_error_from_errno("asprintf");
271 *match = (strcmp(absprefix ? absprefix : path_prefix,
272 worktree->path_prefix) == 0);
273 free(absprefix);
274 return NULL;
277 const char *
278 got_worktree_get_head_ref_name(struct got_worktree *worktree)
280 return worktree->head_ref_name;
283 const struct got_error *
284 got_worktree_set_head_ref(struct got_worktree *worktree,
285 struct got_reference *head_ref)
287 const struct got_error *err = NULL;
288 char *path_got = NULL, *head_ref_name = NULL;
290 if (asprintf(&path_got, "%s/%s", worktree->root_path,
291 GOT_WORKTREE_GOT_DIR) == -1) {
292 err = got_error_from_errno("asprintf");
293 path_got = NULL;
294 goto done;
297 head_ref_name = strdup(got_ref_get_name(head_ref));
298 if (head_ref_name == NULL) {
299 err = got_error_from_errno("strdup");
300 goto done;
303 err = write_head_ref(path_got, head_ref);
304 if (err)
305 goto done;
307 free(worktree->head_ref_name);
308 worktree->head_ref_name = head_ref_name;
309 done:
310 free(path_got);
311 if (err)
312 free(head_ref_name);
313 return err;
316 struct got_object_id *
317 got_worktree_get_base_commit_id(struct got_worktree *worktree)
319 return worktree->base_commit_id;
322 const struct got_error *
323 got_worktree_set_base_commit_id(struct got_worktree *worktree,
324 struct got_repository *repo, struct got_object_id *commit_id)
326 const struct got_error *err;
327 struct got_object *obj = NULL;
328 char *id_str = NULL;
329 char *path_got = NULL;
331 if (asprintf(&path_got, "%s/%s", worktree->root_path,
332 GOT_WORKTREE_GOT_DIR) == -1) {
333 err = got_error_from_errno("asprintf");
334 path_got = NULL;
335 goto done;
338 err = got_object_open(&obj, repo, commit_id);
339 if (err)
340 return err;
342 if (obj->type != GOT_OBJ_TYPE_COMMIT) {
343 err = got_error(GOT_ERR_OBJ_TYPE);
344 goto done;
347 /* Record our base commit. */
348 err = got_object_id_str(&id_str, commit_id);
349 if (err)
350 goto done;
351 err = update_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, id_str);
352 if (err)
353 goto done;
355 free(worktree->base_commit_id);
356 worktree->base_commit_id = got_object_id_dup(commit_id);
357 if (worktree->base_commit_id == NULL) {
358 err = got_error_from_errno("got_object_id_dup");
359 goto done;
361 done:
362 if (obj)
363 got_object_close(obj);
364 free(id_str);
365 free(path_got);
366 return err;
369 const struct got_gotconfig *
370 got_worktree_get_gotconfig(struct got_worktree *worktree)
372 return worktree->gotconfig;
375 static const struct got_error *
376 lock_worktree(struct got_worktree *worktree, int operation)
378 if (flock(worktree->lockfd, operation | LOCK_NB) == -1)
379 return (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY)
380 : got_error_from_errno2("flock",
381 got_worktree_get_root_path(worktree)));
382 return NULL;
385 static const struct got_error *
386 add_dir_on_disk(struct got_worktree *worktree, const char *path)
388 const struct got_error *err = NULL;
389 char *abspath;
391 if (asprintf(&abspath, "%s/%s", worktree->root_path, path) == -1)
392 return got_error_from_errno("asprintf");
394 err = got_path_mkdir(abspath);
395 if (err && err->code == GOT_ERR_ERRNO && errno == EEXIST) {
396 struct stat sb;
397 err = NULL;
398 if (lstat(abspath, &sb) == -1) {
399 err = got_error_from_errno2("lstat", abspath);
400 } else if (!S_ISDIR(sb.st_mode)) {
401 /* TODO directory is obstructed; do something */
402 err = got_error_path(abspath, GOT_ERR_FILE_OBSTRUCTED);
405 free(abspath);
406 return err;
409 static const struct got_error *
410 check_file_contents_equal(int *same, FILE *f1, FILE *f2)
412 const struct got_error *err = NULL;
413 uint8_t fbuf1[8192];
414 uint8_t fbuf2[8192];
415 size_t flen1 = 0, flen2 = 0;
417 *same = 1;
419 for (;;) {
420 flen1 = fread(fbuf1, 1, sizeof(fbuf1), f1);
421 if (flen1 == 0 && ferror(f1)) {
422 err = got_error_from_errno("fread");
423 break;
425 flen2 = fread(fbuf2, 1, sizeof(fbuf2), f2);
426 if (flen2 == 0 && ferror(f2)) {
427 err = got_error_from_errno("fread");
428 break;
430 if (flen1 == 0) {
431 if (flen2 != 0)
432 *same = 0;
433 break;
434 } else if (flen2 == 0) {
435 if (flen1 != 0)
436 *same = 0;
437 break;
438 } else if (flen1 == flen2) {
439 if (memcmp(fbuf1, fbuf2, flen2) != 0) {
440 *same = 0;
441 break;
443 } else {
444 *same = 0;
445 break;
449 return err;
452 static const struct got_error *
453 check_files_equal(int *same, FILE *f1, FILE *f2)
455 struct stat sb;
456 size_t size1, size2;
458 *same = 1;
460 if (fstat(fileno(f1), &sb) != 0)
461 return got_error_from_errno("fstat");
462 size1 = sb.st_size;
464 if (fstat(fileno(f2), &sb) != 0)
465 return got_error_from_errno("fstat");
466 size2 = sb.st_size;
468 if (size1 != size2) {
469 *same = 0;
470 return NULL;
473 if (fseek(f1, 0L, SEEK_SET) == -1)
474 return got_ferror(f1, GOT_ERR_IO);
475 if (fseek(f2, 0L, SEEK_SET) == -1)
476 return got_ferror(f2, GOT_ERR_IO);
478 return check_file_contents_equal(same, f1, f2);
481 static const struct got_error *
482 copy_file_to_fd(off_t *outsize, FILE *f, int outfd)
484 uint8_t fbuf[65536];
485 size_t flen;
486 ssize_t outlen;
488 *outsize = 0;
490 if (fseek(f, 0L, SEEK_SET) == -1)
491 return got_ferror(f, GOT_ERR_IO);
493 for (;;) {
494 flen = fread(fbuf, 1, sizeof(fbuf), f);
495 if (flen == 0) {
496 if (ferror(f))
497 return got_error_from_errno("fread");
498 if (feof(f))
499 break;
501 outlen = write(outfd, fbuf, flen);
502 if (outlen == -1)
503 return got_error_from_errno("write");
504 if (outlen != flen)
505 return got_error(GOT_ERR_IO);
506 *outsize += outlen;
509 return NULL;
512 static const struct got_error *
513 merge_binary_file(int *overlapcnt, int merged_fd,
514 FILE *f_deriv, FILE *f_orig, FILE *f_deriv2,
515 const char *label_deriv, const char *label_orig, const char *label_deriv2,
516 const char *ondisk_path)
518 const struct got_error *err = NULL;
519 int same_content, changed_deriv, changed_deriv2;
520 int fd_orig = -1, fd_deriv = -1, fd_deriv2 = -1;
521 off_t size_orig = 0, size_deriv = 0, size_deriv2 = 0;
522 char *path_orig = NULL, *path_deriv = NULL, *path_deriv2 = NULL;
523 char *base_path_orig = NULL, *base_path_deriv = NULL;
524 char *base_path_deriv2 = NULL;
526 *overlapcnt = 0;
528 err = check_files_equal(&same_content, f_deriv, f_deriv2);
529 if (err)
530 return err;
532 if (same_content)
533 return copy_file_to_fd(&size_deriv, f_deriv, merged_fd);
535 err = check_files_equal(&same_content, f_deriv, f_orig);
536 if (err)
537 return err;
538 changed_deriv = !same_content;
539 err = check_files_equal(&same_content, f_deriv2, f_orig);
540 if (err)
541 return err;
542 changed_deriv2 = !same_content;
544 if (changed_deriv && changed_deriv2) {
545 *overlapcnt = 1;
546 if (asprintf(&base_path_orig, "%s-orig", ondisk_path) == -1) {
547 err = got_error_from_errno("asprintf");
548 goto done;
550 if (asprintf(&base_path_deriv, "%s-1", ondisk_path) == -1) {
551 err = got_error_from_errno("asprintf");
552 goto done;
554 if (asprintf(&base_path_deriv2, "%s-2", ondisk_path) == -1) {
555 err = got_error_from_errno("asprintf");
556 goto done;
558 err = got_opentemp_named_fd(&path_orig, &fd_orig,
559 base_path_orig, "");
560 if (err)
561 goto done;
562 err = got_opentemp_named_fd(&path_deriv, &fd_deriv,
563 base_path_deriv, "");
564 if (err)
565 goto done;
566 err = got_opentemp_named_fd(&path_deriv2, &fd_deriv2,
567 base_path_deriv2, "");
568 if (err)
569 goto done;
570 err = copy_file_to_fd(&size_orig, f_orig, fd_orig);
571 if (err)
572 goto done;
573 err = copy_file_to_fd(&size_deriv, f_deriv, fd_deriv);
574 if (err)
575 goto done;
576 err = copy_file_to_fd(&size_deriv2, f_deriv2, fd_deriv2);
577 if (err)
578 goto done;
579 if (dprintf(merged_fd, "Binary files differ and cannot be "
580 "merged automatically:\n") < 0) {
581 err = got_error_from_errno("dprintf");
582 goto done;
584 if (dprintf(merged_fd, "%s%s%s\nfile %s\n",
585 GOT_DIFF_CONFLICT_MARKER_BEGIN,
586 label_deriv ? " " : "",
587 label_deriv ? label_deriv : "",
588 path_deriv) < 0) {
589 err = got_error_from_errno("dprintf");
590 goto done;
592 if (size_orig > 0) {
593 if (dprintf(merged_fd, "%s%s%s\nfile %s\n",
594 GOT_DIFF_CONFLICT_MARKER_ORIG,
595 label_orig ? " " : "",
596 label_orig ? label_orig : "",
597 path_orig) < 0) {
598 err = got_error_from_errno("dprintf");
599 goto done;
602 if (dprintf(merged_fd, "%s\nfile %s\n%s%s%s\n",
603 GOT_DIFF_CONFLICT_MARKER_SEP,
604 path_deriv2,
605 GOT_DIFF_CONFLICT_MARKER_END,
606 label_deriv2 ? " " : "",
607 label_deriv2 ? label_deriv2 : "") < 0) {
608 err = got_error_from_errno("dprintf");
609 goto done;
611 } else if (changed_deriv)
612 err = copy_file_to_fd(&size_deriv, f_deriv, merged_fd);
613 else if (changed_deriv2)
614 err = copy_file_to_fd(&size_deriv2, f_deriv2, merged_fd);
615 done:
616 if (size_orig == 0 && path_orig && unlink(path_orig) == -1 &&
617 err == NULL)
618 err = got_error_from_errno2("unlink", path_orig);
619 if (fd_orig != -1 && close(fd_orig) == -1 && err == NULL)
620 err = got_error_from_errno2("close", path_orig);
621 if (fd_deriv != -1 && close(fd_deriv) == -1 && err == NULL)
622 err = got_error_from_errno2("close", path_deriv);
623 if (fd_deriv2 != -1 && close(fd_deriv2) == -1 && err == NULL)
624 err = got_error_from_errno2("close", path_deriv2);
625 free(path_orig);
626 free(path_deriv);
627 free(path_deriv2);
628 free(base_path_orig);
629 free(base_path_deriv);
630 free(base_path_deriv2);
631 return err;
634 /*
635 * Perform a 3-way merge where the file f_orig acts as the common
636 * ancestor, the file f_deriv acts as the first derived version,
637 * and the file f_deriv2 acts as the second derived version.
638 * The merge result will be written to a new file at ondisk_path; any
639 * existing file at this path will be replaced.
640 */
641 static const struct got_error *
642 merge_file(int *local_changes_subsumed, struct got_worktree *worktree,
643 FILE *f_orig, FILE *f_deriv, FILE *f_deriv2, const char *ondisk_path,
644 const char *path, uint16_t st_mode,
645 const char *label_orig, const char *label_deriv, const char *label_deriv2,
646 enum got_diff_algorithm diff_algo, struct got_repository *repo,
647 got_worktree_checkout_cb progress_cb, void *progress_arg)
649 const struct got_error *err = NULL;
650 int merged_fd = -1;
651 FILE *f_merged = NULL;
652 char *merged_path = NULL, *base_path = NULL;
653 int overlapcnt = 0;
654 char *parent = NULL;
656 *local_changes_subsumed = 0;
658 err = got_path_dirname(&parent, ondisk_path);
659 if (err)
660 return err;
662 if (asprintf(&base_path, "%s/got-merged", parent) == -1) {
663 err = got_error_from_errno("asprintf");
664 goto done;
667 err = got_opentemp_named_fd(&merged_path, &merged_fd, base_path, "");
668 if (err)
669 goto done;
671 err = got_merge_diff3(&overlapcnt, merged_fd, f_deriv, f_orig,
672 f_deriv2, label_deriv, label_orig, label_deriv2, diff_algo);
673 if (err) {
674 if (err->code != GOT_ERR_FILE_BINARY)
675 goto done;
676 err = merge_binary_file(&overlapcnt, merged_fd, f_deriv,
677 f_orig, f_deriv2, label_deriv, label_orig, label_deriv2,
678 ondisk_path);
679 if (err)
680 goto done;
683 err = (*progress_cb)(progress_arg,
684 overlapcnt > 0 ? GOT_STATUS_CONFLICT : GOT_STATUS_MERGE, path);
685 if (err)
686 goto done;
688 if (fsync(merged_fd) != 0) {
689 err = got_error_from_errno("fsync");
690 goto done;
693 f_merged = fdopen(merged_fd, "r");
694 if (f_merged == NULL) {
695 err = got_error_from_errno("fdopen");
696 goto done;
698 merged_fd = -1;
700 /* Check if a clean merge has subsumed all local changes. */
701 if (overlapcnt == 0) {
702 err = check_files_equal(local_changes_subsumed, f_deriv,
703 f_merged);
704 if (err)
705 goto done;
708 if (fchmod(fileno(f_merged), apply_umask(st_mode)) != 0) {
709 err = got_error_from_errno2("fchmod", merged_path);
710 goto done;
713 if (rename(merged_path, ondisk_path) != 0) {
714 err = got_error_from_errno3("rename", merged_path,
715 ondisk_path);
716 goto done;
718 done:
719 if (err) {
720 if (merged_path)
721 unlink(merged_path);
723 if (merged_fd != -1 && close(merged_fd) == -1 && err == NULL)
724 err = got_error_from_errno("close");
725 if (f_merged && fclose(f_merged) == EOF && err == NULL)
726 err = got_error_from_errno("fclose");
727 free(merged_path);
728 free(base_path);
729 free(parent);
730 return err;
733 static const struct got_error *
734 update_symlink(const char *ondisk_path, const char *target_path,
735 size_t target_len)
737 /* This is not atomic but matches what 'ln -sf' does. */
738 if (unlink(ondisk_path) == -1)
739 return got_error_from_errno2("unlink", ondisk_path);
740 if (symlink(target_path, ondisk_path) == -1)
741 return got_error_from_errno3("symlink", target_path,
742 ondisk_path);
743 return NULL;
746 /*
747 * Overwrite a symlink (or a regular file in case there was a "bad" symlink)
748 * in the work tree with a file that contains conflict markers and the
749 * conflicting target paths of the original version, a "derived version"
750 * of a symlink from an incoming change, and a local version of the symlink.
752 * The original versions's target path can be NULL if it is not available,
753 * such as if both derived versions added a new symlink at the same path.
755 * The incoming derived symlink target is NULL in case the incoming change
756 * has deleted this symlink.
757 */
758 static const struct got_error *
759 install_symlink_conflict(const char *deriv_target,
760 struct got_object_id *deriv_base_commit_id, const char *orig_target,
761 const char *label_orig, const char *local_target, const char *ondisk_path)
763 const struct got_error *err;
764 char *id_str = NULL, *label_deriv = NULL, *path = NULL;
765 FILE *f = NULL;
767 err = got_object_id_str(&id_str, deriv_base_commit_id);
768 if (err)
769 return got_error_from_errno("asprintf");
771 if (asprintf(&label_deriv, "%s: commit %s",
772 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
773 err = got_error_from_errno("asprintf");
774 goto done;
777 err = got_opentemp_named(&path, &f, "got-symlink-conflict", "");
778 if (err)
779 goto done;
781 if (fchmod(fileno(f), apply_umask(GOT_DEFAULT_FILE_MODE)) == -1) {
782 err = got_error_from_errno2("fchmod", path);
783 goto done;
786 if (fprintf(f, "%s %s\n%s\n%s%s%s%s%s\n%s\n%s\n",
787 GOT_DIFF_CONFLICT_MARKER_BEGIN, label_deriv,
788 deriv_target ? deriv_target : "(symlink was deleted)",
789 orig_target ? label_orig : "",
790 orig_target ? "\n" : "",
791 orig_target ? orig_target : "",
792 orig_target ? "\n" : "",
793 GOT_DIFF_CONFLICT_MARKER_SEP,
794 local_target, GOT_DIFF_CONFLICT_MARKER_END) < 0) {
795 err = got_error_from_errno2("fprintf", path);
796 goto done;
799 if (unlink(ondisk_path) == -1) {
800 err = got_error_from_errno2("unlink", ondisk_path);
801 goto done;
803 if (rename(path, ondisk_path) == -1) {
804 err = got_error_from_errno3("rename", path, ondisk_path);
805 goto done;
807 done:
808 if (f != NULL && fclose(f) == EOF && err == NULL)
809 err = got_error_from_errno2("fclose", path);
810 free(path);
811 free(id_str);
812 free(label_deriv);
813 return err;
816 /* forward declaration */
817 static const struct got_error *
818 merge_blob(int *, struct got_worktree *, struct got_blob_object *,
819 const char *, const char *, uint16_t, const char *,
820 struct got_blob_object *, struct got_object_id *,
821 struct got_repository *, got_worktree_checkout_cb, void *);
823 /*
824 * Merge a symlink into the work tree, where blob_orig acts as the common
825 * ancestor, deriv_target is the link target of the first derived version,
826 * and the symlink on disk acts as the second derived version.
827 * Assume that contents of both blobs represent symlinks.
828 */
829 static const struct got_error *
830 merge_symlink(struct got_worktree *worktree,
831 struct got_blob_object *blob_orig, const char *ondisk_path,
832 const char *path, const char *label_orig, const char *deriv_target,
833 struct got_object_id *deriv_base_commit_id, struct got_repository *repo,
834 got_worktree_checkout_cb progress_cb, void *progress_arg)
836 const struct got_error *err = NULL;
837 char *ancestor_target = NULL;
838 struct stat sb;
839 ssize_t ondisk_len, deriv_len;
840 char ondisk_target[PATH_MAX];
841 int have_local_change = 0;
842 int have_incoming_change = 0;
844 if (lstat(ondisk_path, &sb) == -1)
845 return got_error_from_errno2("lstat", ondisk_path);
847 ondisk_len = readlink(ondisk_path, ondisk_target,
848 sizeof(ondisk_target));
849 if (ondisk_len == -1) {
850 err = got_error_from_errno2("readlink",
851 ondisk_path);
852 goto done;
854 ondisk_target[ondisk_len] = '\0';
856 if (blob_orig) {
857 err = got_object_blob_read_to_str(&ancestor_target, blob_orig);
858 if (err)
859 goto done;
862 if (ancestor_target == NULL ||
863 (ondisk_len != strlen(ancestor_target) ||
864 memcmp(ondisk_target, ancestor_target, ondisk_len) != 0))
865 have_local_change = 1;
867 deriv_len = strlen(deriv_target);
868 if (ancestor_target == NULL ||
869 (deriv_len != strlen(ancestor_target) ||
870 memcmp(deriv_target, ancestor_target, deriv_len) != 0))
871 have_incoming_change = 1;
873 if (!have_local_change && !have_incoming_change) {
874 if (ancestor_target) {
875 /* Both sides made the same change. */
876 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
877 path);
878 } else if (deriv_len == ondisk_len &&
879 memcmp(ondisk_target, deriv_target, deriv_len) == 0) {
880 /* Both sides added the same symlink. */
881 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
882 path);
883 } else {
884 /* Both sides added symlinks which don't match. */
885 err = install_symlink_conflict(deriv_target,
886 deriv_base_commit_id, ancestor_target,
887 label_orig, ondisk_target, ondisk_path);
888 if (err)
889 goto done;
890 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
891 path);
893 } else if (!have_local_change && have_incoming_change) {
894 /* Apply the incoming change. */
895 err = update_symlink(ondisk_path, deriv_target,
896 strlen(deriv_target));
897 if (err)
898 goto done;
899 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
900 } else if (have_local_change && have_incoming_change) {
901 if (deriv_len == ondisk_len &&
902 memcmp(deriv_target, ondisk_target, deriv_len) == 0) {
903 /* Both sides made the same change. */
904 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
905 path);
906 } else {
907 err = install_symlink_conflict(deriv_target,
908 deriv_base_commit_id, ancestor_target, label_orig,
909 ondisk_target, ondisk_path);
910 if (err)
911 goto done;
912 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
913 path);
917 done:
918 free(ancestor_target);
919 return err;
922 static const struct got_error *
923 dump_symlink_target_path_to_file(FILE **outfile, const char *ondisk_path)
925 const struct got_error *err = NULL;
926 char target_path[PATH_MAX];
927 ssize_t target_len;
928 size_t n;
929 FILE *f;
931 *outfile = NULL;
933 f = got_opentemp();
934 if (f == NULL)
935 return got_error_from_errno("got_opentemp");
936 target_len = readlink(ondisk_path, target_path, sizeof(target_path));
937 if (target_len == -1) {
938 err = got_error_from_errno2("readlink", ondisk_path);
939 goto done;
941 n = fwrite(target_path, 1, target_len, f);
942 if (n != target_len) {
943 err = got_ferror(f, GOT_ERR_IO);
944 goto done;
946 if (fflush(f) == EOF) {
947 err = got_error_from_errno("fflush");
948 goto done;
950 if (fseek(f, 0L, SEEK_SET) == -1) {
951 err = got_ferror(f, GOT_ERR_IO);
952 goto done;
954 done:
955 if (err)
956 fclose(f);
957 else
958 *outfile = f;
959 return err;
962 /*
963 * Perform a 3-way merge where blob_orig acts as the common ancestor,
964 * blob_deriv acts as the first derived version, and the file on disk
965 * acts as the second derived version.
966 */
967 static const struct got_error *
968 merge_blob(int *local_changes_subsumed, struct got_worktree *worktree,
969 struct got_blob_object *blob_orig, const char *ondisk_path,
970 const char *path, uint16_t st_mode, const char *label_orig,
971 struct got_blob_object *blob_deriv,
972 struct got_object_id *deriv_base_commit_id, struct got_repository *repo,
973 got_worktree_checkout_cb progress_cb, void *progress_arg)
975 const struct got_error *err = NULL;
976 FILE *f_orig = NULL, *f_deriv = NULL, *f_deriv2 = NULL;
977 char *blob_orig_path = NULL;
978 char *blob_deriv_path = NULL, *base_path = NULL, *id_str = NULL;
979 char *label_deriv = NULL, *parent = NULL;
981 *local_changes_subsumed = 0;
983 err = got_path_dirname(&parent, ondisk_path);
984 if (err)
985 return err;
987 if (blob_orig) {
988 if (asprintf(&base_path, "%s/got-merge-blob-orig",
989 parent) == -1) {
990 err = got_error_from_errno("asprintf");
991 base_path = NULL;
992 goto done;
995 err = got_opentemp_named(&blob_orig_path, &f_orig,
996 base_path, "");
997 if (err)
998 goto done;
999 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_orig,
1000 blob_orig);
1001 if (err)
1002 goto done;
1003 free(base_path);
1004 } else {
1006 * No common ancestor exists. This is an "add vs add" conflict
1007 * and we simply use an empty ancestor file to make both files
1008 * appear in the merged result in their entirety.
1010 f_orig = got_opentemp();
1011 if (f_orig == NULL) {
1012 err = got_error_from_errno("got_opentemp");
1013 goto done;
1017 if (asprintf(&base_path, "%s/got-merge-blob-deriv", parent) == -1) {
1018 err = got_error_from_errno("asprintf");
1019 base_path = NULL;
1020 goto done;
1023 err = got_opentemp_named(&blob_deriv_path, &f_deriv, base_path, "");
1024 if (err)
1025 goto done;
1026 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_deriv,
1027 blob_deriv);
1028 if (err)
1029 goto done;
1031 err = got_object_id_str(&id_str, deriv_base_commit_id);
1032 if (err)
1033 goto done;
1034 if (asprintf(&label_deriv, "%s: commit %s",
1035 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
1036 err = got_error_from_errno("asprintf");
1037 goto done;
1041 * In order the run a 3-way merge with a symlink we copy the symlink's
1042 * target path into a temporary file and use that file with diff3.
1044 if (S_ISLNK(st_mode)) {
1045 err = dump_symlink_target_path_to_file(&f_deriv2, ondisk_path);
1046 if (err)
1047 goto done;
1048 } else {
1049 int fd;
1050 fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
1051 if (fd == -1) {
1052 err = got_error_from_errno2("open", ondisk_path);
1053 goto done;
1055 f_deriv2 = fdopen(fd, "r");
1056 if (f_deriv2 == NULL) {
1057 err = got_error_from_errno2("fdopen", ondisk_path);
1058 close(fd);
1059 goto done;
1063 err = merge_file(local_changes_subsumed, worktree, f_orig, f_deriv,
1064 f_deriv2, ondisk_path, path, st_mode, label_orig, label_deriv,
1065 NULL, GOT_DIFF_ALGORITHM_MYERS, repo, progress_cb, progress_arg);
1066 done:
1067 if (f_orig && fclose(f_orig) == EOF && err == NULL)
1068 err = got_error_from_errno("fclose");
1069 if (f_deriv && fclose(f_deriv) == EOF && err == NULL)
1070 err = got_error_from_errno("fclose");
1071 if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL)
1072 err = got_error_from_errno("fclose");
1073 free(base_path);
1074 if (blob_orig_path) {
1075 unlink(blob_orig_path);
1076 free(blob_orig_path);
1078 if (blob_deriv_path) {
1079 unlink(blob_deriv_path);
1080 free(blob_deriv_path);
1082 free(id_str);
1083 free(label_deriv);
1084 free(parent);
1085 return err;
1088 static const struct got_error *
1089 create_fileindex_entry(struct got_fileindex_entry **new_iep,
1090 struct got_fileindex *fileindex, struct got_object_id *base_commit_id,
1091 int wt_fd, const char *path, struct got_object_id *blob_id)
1093 const struct got_error *err = NULL;
1094 struct got_fileindex_entry *new_ie;
1096 *new_iep = NULL;
1098 err = got_fileindex_entry_alloc(&new_ie, path);
1099 if (err)
1100 return err;
1102 err = got_fileindex_entry_update(new_ie, wt_fd, path,
1103 blob_id->sha1, base_commit_id->sha1, 1);
1104 if (err)
1105 goto done;
1107 err = got_fileindex_entry_add(fileindex, new_ie);
1108 done:
1109 if (err)
1110 got_fileindex_entry_free(new_ie);
1111 else
1112 *new_iep = new_ie;
1113 return err;
1116 static mode_t
1117 get_ondisk_perms(int executable, mode_t st_mode)
1119 mode_t xbits = S_IXUSR;
1121 if (executable) {
1122 /* Map read bits to execute bits. */
1123 if (st_mode & S_IRGRP)
1124 xbits |= S_IXGRP;
1125 if (st_mode & S_IROTH)
1126 xbits |= S_IXOTH;
1127 return st_mode | xbits;
1130 return st_mode;
1133 static mode_t
1134 apply_umask(mode_t mode)
1136 mode_t um;
1138 um = umask(000);
1139 umask(um);
1140 return mode & ~um;
1143 /* forward declaration */
1144 static const struct got_error *
1145 install_blob(struct got_worktree *worktree, const char *ondisk_path,
1146 const char *path, mode_t te_mode, mode_t st_mode,
1147 struct got_blob_object *blob, int restoring_missing_file,
1148 int reverting_versioned_file, int installing_bad_symlink,
1149 int path_is_unversioned, struct got_repository *repo,
1150 got_worktree_checkout_cb progress_cb, void *progress_arg);
1153 * This function assumes that the provided symlink target points at a
1154 * safe location in the work tree!
1156 static const struct got_error *
1157 replace_existing_symlink(int *did_something, const char *ondisk_path,
1158 const char *target_path, size_t target_len)
1160 const struct got_error *err = NULL;
1161 ssize_t elen;
1162 char etarget[PATH_MAX];
1163 int fd;
1165 *did_something = 0;
1168 * "Bad" symlinks (those pointing outside the work tree or into the
1169 * .got directory) are installed in the work tree as a regular file
1170 * which contains the bad symlink target path.
1171 * The new symlink target has already been checked for safety by our
1172 * caller. If we can successfully open a regular file then we simply
1173 * replace this file with a symlink below.
1175 fd = open(ondisk_path, O_RDWR | O_EXCL | O_NOFOLLOW | O_CLOEXEC);
1176 if (fd == -1) {
1177 if (!got_err_open_nofollow_on_symlink())
1178 return got_error_from_errno2("open", ondisk_path);
1180 /* We are updating an existing on-disk symlink. */
1181 elen = readlink(ondisk_path, etarget, sizeof(etarget));
1182 if (elen == -1)
1183 return got_error_from_errno2("readlink", ondisk_path);
1185 if (elen == target_len &&
1186 memcmp(etarget, target_path, target_len) == 0)
1187 return NULL; /* nothing to do */
1190 *did_something = 1;
1191 err = update_symlink(ondisk_path, target_path, target_len);
1192 if (fd != -1 && close(fd) == -1 && err == NULL)
1193 err = got_error_from_errno2("close", ondisk_path);
1194 return err;
1197 static const struct got_error *
1198 is_bad_symlink_target(int *is_bad_symlink, const char *target_path,
1199 size_t target_len, const char *ondisk_path, const char *wtroot_path)
1201 const struct got_error *err = NULL;
1202 char canonpath[PATH_MAX];
1203 char *path_got = NULL;
1205 *is_bad_symlink = 0;
1207 if (target_len >= sizeof(canonpath)) {
1208 *is_bad_symlink = 1;
1209 return NULL;
1213 * We do not use realpath(3) to resolve the symlink's target
1214 * path because we don't want to resolve symlinks recursively.
1215 * Instead we make the path absolute and then canonicalize it.
1216 * Relative symlink target lookup should begin at the directory
1217 * in which the blob object is being installed.
1219 if (!got_path_is_absolute(target_path)) {
1220 char *abspath, *parent;
1221 err = got_path_dirname(&parent, ondisk_path);
1222 if (err)
1223 return err;
1224 if (asprintf(&abspath, "%s/%s", parent, target_path) == -1) {
1225 free(parent);
1226 return got_error_from_errno("asprintf");
1228 free(parent);
1229 if (strlen(abspath) >= sizeof(canonpath)) {
1230 err = got_error_path(abspath, GOT_ERR_BAD_PATH);
1231 free(abspath);
1232 return err;
1234 err = got_canonpath(abspath, canonpath, sizeof(canonpath));
1235 free(abspath);
1236 if (err)
1237 return err;
1238 } else {
1239 err = got_canonpath(target_path, canonpath, sizeof(canonpath));
1240 if (err)
1241 return err;
1244 /* Only allow symlinks pointing at paths within the work tree. */
1245 if (!got_path_is_child(canonpath, wtroot_path, strlen(wtroot_path))) {
1246 *is_bad_symlink = 1;
1247 return NULL;
1250 /* Do not allow symlinks pointing into the .got directory. */
1251 if (asprintf(&path_got, "%s/%s", wtroot_path,
1252 GOT_WORKTREE_GOT_DIR) == -1)
1253 return got_error_from_errno("asprintf");
1254 if (got_path_is_child(canonpath, path_got, strlen(path_got)))
1255 *is_bad_symlink = 1;
1257 free(path_got);
1258 return NULL;
1261 static const struct got_error *
1262 install_symlink(int *is_bad_symlink, struct got_worktree *worktree,
1263 const char *ondisk_path, const char *path, struct got_blob_object *blob,
1264 int restoring_missing_file, int reverting_versioned_file,
1265 int path_is_unversioned, int allow_bad_symlinks,
1266 struct got_repository *repo,
1267 got_worktree_checkout_cb progress_cb, void *progress_arg)
1269 const struct got_error *err = NULL;
1270 char target_path[PATH_MAX];
1271 size_t len, target_len = 0;
1272 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1273 size_t hdrlen = got_object_blob_get_hdrlen(blob);
1275 *is_bad_symlink = 0;
1278 * Blob object content specifies the target path of the link.
1279 * If a symbolic link cannot be installed we instead create
1280 * a regular file which contains the link target path stored
1281 * in the blob object.
1283 do {
1284 err = got_object_blob_read_block(&len, blob);
1285 if (err)
1286 return err;
1288 if (len + target_len >= sizeof(target_path)) {
1289 /* Path too long; install as a regular file. */
1290 *is_bad_symlink = 1;
1291 got_object_blob_rewind(blob);
1292 return install_blob(worktree, ondisk_path, path,
1293 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1294 restoring_missing_file, reverting_versioned_file,
1295 1, path_is_unversioned, repo, progress_cb,
1296 progress_arg);
1298 if (len > 0) {
1299 /* Skip blob object header first time around. */
1300 memcpy(target_path + target_len, buf + hdrlen,
1301 len - hdrlen);
1302 target_len += len - hdrlen;
1303 hdrlen = 0;
1305 } while (len != 0);
1306 target_path[target_len] = '\0';
1308 err = is_bad_symlink_target(is_bad_symlink, target_path, target_len,
1309 ondisk_path, worktree->root_path);
1310 if (err)
1311 return err;
1313 if (*is_bad_symlink && !allow_bad_symlinks) {
1314 /* install as a regular file */
1315 got_object_blob_rewind(blob);
1316 err = install_blob(worktree, ondisk_path, path,
1317 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1318 restoring_missing_file, reverting_versioned_file, 1,
1319 path_is_unversioned, repo, progress_cb, progress_arg);
1320 return err;
1323 if (symlink(target_path, ondisk_path) == -1) {
1324 if (errno == EEXIST) {
1325 int symlink_replaced;
1326 if (path_is_unversioned) {
1327 err = (*progress_cb)(progress_arg,
1328 GOT_STATUS_UNVERSIONED, path);
1329 return err;
1331 err = replace_existing_symlink(&symlink_replaced,
1332 ondisk_path, target_path, target_len);
1333 if (err)
1334 return err;
1335 if (progress_cb) {
1336 if (symlink_replaced) {
1337 err = (*progress_cb)(progress_arg,
1338 reverting_versioned_file ?
1339 GOT_STATUS_REVERT :
1340 GOT_STATUS_UPDATE, path);
1341 } else {
1342 err = (*progress_cb)(progress_arg,
1343 GOT_STATUS_EXISTS, path);
1346 return err; /* Nothing else to do. */
1349 if (errno == ENOENT) {
1350 char *parent;
1351 err = got_path_dirname(&parent, ondisk_path);
1352 if (err)
1353 return err;
1354 err = add_dir_on_disk(worktree, parent);
1355 free(parent);
1356 if (err)
1357 return err;
1359 * Retry, and fall through to error handling
1360 * below if this second attempt fails.
1362 if (symlink(target_path, ondisk_path) != -1) {
1363 err = NULL; /* success */
1364 return err;
1368 /* Handle errors from first or second creation attempt. */
1369 if (errno == ENAMETOOLONG) {
1370 /* bad target path; install as a regular file */
1371 *is_bad_symlink = 1;
1372 got_object_blob_rewind(blob);
1373 err = install_blob(worktree, ondisk_path, path,
1374 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1375 restoring_missing_file, reverting_versioned_file, 1,
1376 path_is_unversioned, repo,
1377 progress_cb, progress_arg);
1378 } else if (errno == ENOTDIR) {
1379 err = got_error_path(ondisk_path,
1380 GOT_ERR_FILE_OBSTRUCTED);
1381 } else {
1382 err = got_error_from_errno3("symlink",
1383 target_path, ondisk_path);
1385 } else if (progress_cb)
1386 err = (*progress_cb)(progress_arg, reverting_versioned_file ?
1387 GOT_STATUS_REVERT : GOT_STATUS_ADD, path);
1388 return err;
1391 static const struct got_error *
1392 install_blob(struct got_worktree *worktree, const char *ondisk_path,
1393 const char *path, mode_t te_mode, mode_t st_mode,
1394 struct got_blob_object *blob, int restoring_missing_file,
1395 int reverting_versioned_file, int installing_bad_symlink,
1396 int path_is_unversioned, struct got_repository *repo,
1397 got_worktree_checkout_cb progress_cb, void *progress_arg)
1399 const struct got_error *err = NULL;
1400 int fd = -1;
1401 size_t len, hdrlen;
1402 int update = 0;
1403 char *tmppath = NULL;
1404 mode_t mode;
1406 mode = get_ondisk_perms(te_mode & S_IXUSR, GOT_DEFAULT_FILE_MODE);
1407 fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW |
1408 O_CLOEXEC, mode);
1409 if (fd == -1) {
1410 if (errno == ENOENT) {
1411 char *parent;
1412 err = got_path_dirname(&parent, path);
1413 if (err)
1414 return err;
1415 err = add_dir_on_disk(worktree, parent);
1416 free(parent);
1417 if (err)
1418 return err;
1419 fd = open(ondisk_path,
1420 O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
1421 mode);
1422 if (fd == -1)
1423 return got_error_from_errno2("open",
1424 ondisk_path);
1425 } else if (errno == EEXIST) {
1426 if (path_is_unversioned) {
1427 err = (*progress_cb)(progress_arg,
1428 GOT_STATUS_UNVERSIONED, path);
1429 goto done;
1431 if (!(S_ISLNK(st_mode) && S_ISREG(te_mode)) &&
1432 !S_ISREG(st_mode) && !installing_bad_symlink) {
1433 /* TODO file is obstructed; do something */
1434 err = got_error_path(ondisk_path,
1435 GOT_ERR_FILE_OBSTRUCTED);
1436 goto done;
1437 } else {
1438 err = got_opentemp_named_fd(&tmppath, &fd,
1439 ondisk_path, "");
1440 if (err)
1441 goto done;
1442 update = 1;
1444 if (fchmod(fd, apply_umask(mode)) == -1) {
1445 err = got_error_from_errno2("fchmod",
1446 tmppath);
1447 goto done;
1450 } else
1451 return got_error_from_errno2("open", ondisk_path);
1454 if (progress_cb) {
1455 if (restoring_missing_file)
1456 err = (*progress_cb)(progress_arg, GOT_STATUS_MISSING,
1457 path);
1458 else if (reverting_versioned_file)
1459 err = (*progress_cb)(progress_arg, GOT_STATUS_REVERT,
1460 path);
1461 else
1462 err = (*progress_cb)(progress_arg,
1463 update ? GOT_STATUS_UPDATE : GOT_STATUS_ADD, path);
1464 if (err)
1465 goto done;
1468 hdrlen = got_object_blob_get_hdrlen(blob);
1469 do {
1470 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1471 err = got_object_blob_read_block(&len, blob);
1472 if (err)
1473 break;
1474 if (len > 0) {
1475 /* Skip blob object header first time around. */
1476 ssize_t outlen = write(fd, buf + hdrlen, len - hdrlen);
1477 if (outlen == -1) {
1478 err = got_error_from_errno("write");
1479 goto done;
1480 } else if (outlen != len - hdrlen) {
1481 err = got_error(GOT_ERR_IO);
1482 goto done;
1484 hdrlen = 0;
1486 } while (len != 0);
1488 if (fsync(fd) != 0) {
1489 err = got_error_from_errno("fsync");
1490 goto done;
1493 if (update) {
1494 if (S_ISLNK(st_mode) && unlink(ondisk_path) == -1) {
1495 err = got_error_from_errno2("unlink", ondisk_path);
1496 goto done;
1498 if (rename(tmppath, ondisk_path) != 0) {
1499 err = got_error_from_errno3("rename", tmppath,
1500 ondisk_path);
1501 goto done;
1503 free(tmppath);
1504 tmppath = NULL;
1507 done:
1508 if (fd != -1 && close(fd) == -1 && err == NULL)
1509 err = got_error_from_errno("close");
1510 if (tmppath != NULL && unlink(tmppath) == -1 && err == NULL)
1511 err = got_error_from_errno2("unlink", tmppath);
1512 free(tmppath);
1513 return err;
1517 * Upgrade STATUS_MODIFY to STATUS_CONFLICT if a
1518 * conflict marker is found in newly added lines only.
1520 static const struct got_error *
1521 get_modified_file_content_status(unsigned char *status,
1522 struct got_blob_object *blob, const char *path, struct stat *sb,
1523 FILE *ondisk_file)
1525 const struct got_error *err = NULL;
1526 const char *markers[3] = {
1527 GOT_DIFF_CONFLICT_MARKER_BEGIN,
1528 GOT_DIFF_CONFLICT_MARKER_SEP,
1529 GOT_DIFF_CONFLICT_MARKER_END
1531 FILE *f = NULL, *f1 = NULL;
1532 int i = 0;
1533 char *line = NULL;
1534 size_t linesize = 0;
1535 ssize_t linelen;
1536 off_t sz1 = 0;
1538 if (*status == GOT_STATUS_MODIFY) {
1539 f = got_opentemp();
1540 if (f == NULL)
1541 return got_error_from_errno("got_opentemp");
1543 f1 = got_opentemp();
1544 if (f1 == NULL) {
1545 err = got_error_from_errno("got_opentemp");
1546 goto done;
1549 if (blob) {
1550 err = got_object_blob_dump_to_file(&sz1, NULL, NULL,
1551 f1, blob);
1552 if (err)
1553 goto done;
1556 err = got_diff_blob_file(blob, f1, sz1, NULL, ondisk_file, 1,
1557 sb, path, GOT_DIFF_ALGORITHM_MYERS, 0, 0, 0, NULL, f);
1558 if (err)
1559 goto done;
1561 if (fflush(f) == EOF) {
1562 err = got_error_from_errno("fflush");
1563 goto done;
1565 if (fseeko(f, 0L, SEEK_SET) == -1) {
1566 err = got_error_from_errno("fseek");
1567 goto done;
1571 while (*status == GOT_STATUS_MODIFY) {
1572 linelen = getline(&line, &linesize, f);
1573 if (linelen == -1) {
1574 if (feof(f))
1575 break;
1576 err = got_ferror(f, GOT_ERR_IO);
1577 break;
1580 if (*line == '+' &&
1581 strncmp(line + 1, markers[i], strlen(markers[i])) == 0) {
1582 if (strcmp(markers[i], GOT_DIFF_CONFLICT_MARKER_END)
1583 == 0)
1584 *status = GOT_STATUS_CONFLICT;
1585 else
1586 i++;
1590 done:
1591 free(line);
1592 if (f != NULL && fclose(f) == EOF && err == NULL)
1593 err = got_error_from_errno("fclose");
1594 if (f1 != NULL && fclose(f1) == EOF && err == NULL)
1595 err = got_error_from_errno("fclose");
1597 return err;
1600 static int
1601 xbit_differs(struct got_fileindex_entry *ie, uint16_t st_mode)
1603 mode_t ie_mode = got_fileindex_perms_to_st(ie);
1604 return ((ie_mode & S_IXUSR) != (st_mode & S_IXUSR));
1607 static int
1608 stat_info_differs(struct got_fileindex_entry *ie, struct stat *sb)
1610 return !(ie->ctime_sec == sb->st_ctim.tv_sec &&
1611 ie->ctime_nsec == sb->st_ctim.tv_nsec &&
1612 ie->mtime_sec == sb->st_mtim.tv_sec &&
1613 ie->mtime_nsec == sb->st_mtim.tv_nsec &&
1614 ie->size == (sb->st_size & 0xffffffff) &&
1615 !xbit_differs(ie, sb->st_mode));
1618 static unsigned char
1619 get_staged_status(struct got_fileindex_entry *ie)
1621 switch (got_fileindex_entry_stage_get(ie)) {
1622 case GOT_FILEIDX_STAGE_ADD:
1623 return GOT_STATUS_ADD;
1624 case GOT_FILEIDX_STAGE_DELETE:
1625 return GOT_STATUS_DELETE;
1626 case GOT_FILEIDX_STAGE_MODIFY:
1627 return GOT_STATUS_MODIFY;
1628 default:
1629 return GOT_STATUS_NO_CHANGE;
1633 static const struct got_error *
1634 get_symlink_modification_status(unsigned char *status,
1635 struct got_fileindex_entry *ie, const char *abspath,
1636 int dirfd, const char *de_name, struct got_blob_object *blob)
1638 const struct got_error *err = NULL;
1639 char target_path[PATH_MAX];
1640 char etarget[PATH_MAX];
1641 ssize_t elen;
1642 size_t len, target_len = 0;
1643 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1644 size_t hdrlen = got_object_blob_get_hdrlen(blob);
1646 *status = GOT_STATUS_NO_CHANGE;
1648 /* Blob object content specifies the target path of the link. */
1649 do {
1650 err = got_object_blob_read_block(&len, blob);
1651 if (err)
1652 return err;
1653 if (len + target_len >= sizeof(target_path)) {
1655 * Should not happen. The blob contents were OK
1656 * when this symlink was installed.
1658 return got_error(GOT_ERR_NO_SPACE);
1660 if (len > 0) {
1661 /* Skip blob object header first time around. */
1662 memcpy(target_path + target_len, buf + hdrlen,
1663 len - hdrlen);
1664 target_len += len - hdrlen;
1665 hdrlen = 0;
1667 } while (len != 0);
1668 target_path[target_len] = '\0';
1670 if (dirfd != -1) {
1671 elen = readlinkat(dirfd, de_name, etarget, sizeof(etarget));
1672 if (elen == -1)
1673 return got_error_from_errno2("readlinkat", abspath);
1674 } else {
1675 elen = readlink(abspath, etarget, sizeof(etarget));
1676 if (elen == -1)
1677 return got_error_from_errno2("readlink", abspath);
1680 if (elen != target_len || memcmp(etarget, target_path, target_len) != 0)
1681 *status = GOT_STATUS_MODIFY;
1683 return NULL;
1686 static const struct got_error *
1687 get_file_status(unsigned char *status, struct stat *sb,
1688 struct got_fileindex_entry *ie, const char *abspath,
1689 int dirfd, const char *de_name, struct got_repository *repo)
1691 const struct got_error *err = NULL;
1692 struct got_object_id id;
1693 size_t hdrlen;
1694 int fd = -1, fd1 = -1;
1695 FILE *f = NULL;
1696 uint8_t fbuf[8192];
1697 struct got_blob_object *blob = NULL;
1698 size_t flen, blen;
1699 unsigned char staged_status;
1701 staged_status = get_staged_status(ie);
1702 *status = GOT_STATUS_NO_CHANGE;
1703 memset(sb, 0, sizeof(*sb));
1706 * Whenever the caller provides a directory descriptor and a
1707 * directory entry name for the file, use them! This prevents
1708 * race conditions if filesystem paths change beneath our feet.
1710 if (dirfd != -1) {
1711 if (fstatat(dirfd, de_name, sb, AT_SYMLINK_NOFOLLOW) == -1) {
1712 if (errno == ENOENT) {
1713 if (got_fileindex_entry_has_file_on_disk(ie))
1714 *status = GOT_STATUS_MISSING;
1715 else
1716 *status = GOT_STATUS_DELETE;
1717 goto done;
1719 err = got_error_from_errno2("fstatat", abspath);
1720 goto done;
1722 } else {
1723 fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
1724 if (fd == -1 && errno != ENOENT &&
1725 !got_err_open_nofollow_on_symlink())
1726 return got_error_from_errno2("open", abspath);
1727 else if (fd == -1 && got_err_open_nofollow_on_symlink()) {
1728 if (lstat(abspath, sb) == -1)
1729 return got_error_from_errno2("lstat", abspath);
1730 } else if (fd == -1 || fstat(fd, sb) == -1) {
1731 if (errno == ENOENT) {
1732 if (got_fileindex_entry_has_file_on_disk(ie))
1733 *status = GOT_STATUS_MISSING;
1734 else
1735 *status = GOT_STATUS_DELETE;
1736 goto done;
1738 err = got_error_from_errno2("fstat", abspath);
1739 goto done;
1743 if (!S_ISREG(sb->st_mode) && !S_ISLNK(sb->st_mode)) {
1744 *status = GOT_STATUS_OBSTRUCTED;
1745 goto done;
1748 if (!got_fileindex_entry_has_file_on_disk(ie)) {
1749 *status = GOT_STATUS_DELETE;
1750 goto done;
1751 } else if (!got_fileindex_entry_has_blob(ie) &&
1752 staged_status != GOT_STATUS_ADD) {
1753 *status = GOT_STATUS_ADD;
1754 goto done;
1757 if (!stat_info_differs(ie, sb))
1758 goto done;
1760 if (S_ISLNK(sb->st_mode) &&
1761 got_fileindex_entry_filetype_get(ie) != GOT_FILEIDX_MODE_SYMLINK) {
1762 *status = GOT_STATUS_MODIFY;
1763 goto done;
1766 if (staged_status == GOT_STATUS_MODIFY ||
1767 staged_status == GOT_STATUS_ADD)
1768 got_fileindex_entry_get_staged_blob_id(&id, ie);
1769 else
1770 got_fileindex_entry_get_blob_id(&id, ie);
1772 fd1 = got_opentempfd();
1773 if (fd1 == -1) {
1774 err = got_error_from_errno("got_opentempfd");
1775 goto done;
1777 err = got_object_open_as_blob(&blob, repo, &id, sizeof(fbuf), fd1);
1778 if (err)
1779 goto done;
1781 if (S_ISLNK(sb->st_mode)) {
1782 err = get_symlink_modification_status(status, ie,
1783 abspath, dirfd, de_name, blob);
1784 goto done;
1787 if (dirfd != -1) {
1788 fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
1789 if (fd == -1) {
1790 err = got_error_from_errno2("openat", abspath);
1791 goto done;
1795 f = fdopen(fd, "r");
1796 if (f == NULL) {
1797 err = got_error_from_errno2("fdopen", abspath);
1798 goto done;
1800 fd = -1;
1801 hdrlen = got_object_blob_get_hdrlen(blob);
1802 for (;;) {
1803 const uint8_t *bbuf = got_object_blob_get_read_buf(blob);
1804 err = got_object_blob_read_block(&blen, blob);
1805 if (err)
1806 goto done;
1807 /* Skip length of blob object header first time around. */
1808 flen = fread(fbuf, 1, sizeof(fbuf) - hdrlen, f);
1809 if (flen == 0 && ferror(f)) {
1810 err = got_error_from_errno("fread");
1811 goto done;
1813 if (blen - hdrlen == 0) {
1814 if (flen != 0)
1815 *status = GOT_STATUS_MODIFY;
1816 break;
1817 } else if (flen == 0) {
1818 if (blen - hdrlen != 0)
1819 *status = GOT_STATUS_MODIFY;
1820 break;
1821 } else if (blen - hdrlen == flen) {
1822 /* Skip blob object header first time around. */
1823 if (memcmp(bbuf + hdrlen, fbuf, flen) != 0) {
1824 *status = GOT_STATUS_MODIFY;
1825 break;
1827 } else {
1828 *status = GOT_STATUS_MODIFY;
1829 break;
1831 hdrlen = 0;
1834 if (*status == GOT_STATUS_MODIFY) {
1835 rewind(f);
1836 err = get_modified_file_content_status(status, blob, ie->path,
1837 sb, f);
1838 } else if (xbit_differs(ie, sb->st_mode))
1839 *status = GOT_STATUS_MODE_CHANGE;
1840 done:
1841 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
1842 err = got_error_from_errno("close");
1843 if (blob)
1844 got_object_blob_close(blob);
1845 if (f != NULL && fclose(f) == EOF && err == NULL)
1846 err = got_error_from_errno2("fclose", abspath);
1847 if (fd != -1 && close(fd) == -1 && err == NULL)
1848 err = got_error_from_errno2("close", abspath);
1849 return err;
1853 * Update timestamps in the file index if a file is unmodified and
1854 * we had to run a full content comparison to find out.
1856 static const struct got_error *
1857 sync_timestamps(int wt_fd, const char *path, unsigned char status,
1858 struct got_fileindex_entry *ie, struct stat *sb)
1860 if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb))
1861 return got_fileindex_entry_update(ie, wt_fd, path,
1862 ie->blob_sha1, ie->commit_sha1, 1);
1864 return NULL;
1867 static const struct got_error *
1868 update_blob(struct got_worktree *worktree,
1869 struct got_fileindex *fileindex, struct got_fileindex_entry *ie,
1870 struct got_tree_entry *te, const char *path,
1871 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
1872 void *progress_arg)
1874 const struct got_error *err = NULL;
1875 struct got_blob_object *blob = NULL;
1876 char *ondisk_path = NULL;
1877 unsigned char status = GOT_STATUS_NO_CHANGE;
1878 struct stat sb;
1879 int fd1 = -1, fd2 = -1;
1881 if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, path) == -1)
1882 return got_error_from_errno("asprintf");
1884 if (ie) {
1885 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE) {
1886 err = got_error_path(ie->path, GOT_ERR_FILE_STAGED);
1887 goto done;
1889 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
1890 repo);
1891 if (err)
1892 goto done;
1893 if (status == GOT_STATUS_MISSING || status == GOT_STATUS_DELETE)
1894 sb.st_mode = got_fileindex_perms_to_st(ie);
1895 } else {
1896 if (stat(ondisk_path, &sb) == -1) {
1897 if (errno != ENOENT) {
1898 err = got_error_from_errno2("stat",
1899 ondisk_path);
1900 goto done;
1902 sb.st_mode = GOT_DEFAULT_FILE_MODE;
1903 status = GOT_STATUS_UNVERSIONED;
1904 } else {
1905 if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode))
1906 status = GOT_STATUS_UNVERSIONED;
1907 else
1908 status = GOT_STATUS_OBSTRUCTED;
1912 if (status == GOT_STATUS_OBSTRUCTED) {
1913 if (ie)
1914 got_fileindex_entry_mark_skipped(ie);
1915 err = (*progress_cb)(progress_arg, status, path);
1916 goto done;
1918 if (status == GOT_STATUS_CONFLICT) {
1919 if (ie)
1920 got_fileindex_entry_mark_skipped(ie);
1921 err = (*progress_cb)(progress_arg, GOT_STATUS_CANNOT_UPDATE,
1922 path);
1923 goto done;
1926 if (ie && status != GOT_STATUS_MISSING && S_ISREG(sb.st_mode) &&
1927 (S_ISLNK(te->mode) ||
1928 (te->mode & S_IXUSR) == (sb.st_mode & S_IXUSR))) {
1930 * This is a regular file or an installed bad symlink.
1931 * If the file index indicates that this file is already
1932 * up-to-date with respect to the repository we can skip
1933 * updating contents of this file.
1935 if (got_fileindex_entry_has_commit(ie) &&
1936 memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
1937 SHA1_DIGEST_LENGTH) == 0) {
1938 /* Same commit. */
1939 err = sync_timestamps(worktree->root_fd,
1940 path, status, ie, &sb);
1941 if (err)
1942 goto done;
1943 err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
1944 path);
1945 goto done;
1947 if (got_fileindex_entry_has_blob(ie) &&
1948 memcmp(ie->blob_sha1, te->id.sha1,
1949 SHA1_DIGEST_LENGTH) == 0) {
1950 /* Different commit but the same blob. */
1951 err = sync_timestamps(worktree->root_fd,
1952 path, status, ie, &sb);
1953 if (err)
1954 goto done;
1955 err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
1956 path);
1957 goto done;
1961 fd1 = got_opentempfd();
1962 if (fd1 == -1) {
1963 err = got_error_from_errno("got_opentempfd");
1964 goto done;
1966 err = got_object_open_as_blob(&blob, repo, &te->id, 8192, fd1);
1967 if (err)
1968 goto done;
1970 if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_ADD) {
1971 int update_timestamps;
1972 struct got_blob_object *blob2 = NULL;
1973 char *label_orig = NULL;
1974 if (got_fileindex_entry_has_blob(ie)) {
1975 fd2 = got_opentempfd();
1976 if (fd2 == -1) {
1977 err = got_error_from_errno("got_opentempfd");
1978 goto done;
1980 struct got_object_id id2;
1981 got_fileindex_entry_get_blob_id(&id2, ie);
1982 err = got_object_open_as_blob(&blob2, repo, &id2, 8192,
1983 fd2);
1984 if (err)
1985 goto done;
1987 if (got_fileindex_entry_has_commit(ie)) {
1988 char id_str[SHA1_DIGEST_STRING_LENGTH];
1989 if (got_sha1_digest_to_str(ie->commit_sha1, id_str,
1990 sizeof(id_str)) == NULL) {
1991 err = got_error_path(id_str,
1992 GOT_ERR_BAD_OBJ_ID_STR);
1993 goto done;
1995 if (asprintf(&label_orig, "%s: commit %s",
1996 GOT_MERGE_LABEL_BASE, id_str) == -1) {
1997 err = got_error_from_errno("asprintf");
1998 goto done;
2001 if (S_ISLNK(te->mode) && S_ISLNK(sb.st_mode)) {
2002 char *link_target;
2003 err = got_object_blob_read_to_str(&link_target, blob);
2004 if (err)
2005 goto done;
2006 err = merge_symlink(worktree, blob2, ondisk_path, path,
2007 label_orig, link_target, worktree->base_commit_id,
2008 repo, progress_cb, progress_arg);
2009 free(link_target);
2010 } else {
2011 err = merge_blob(&update_timestamps, worktree, blob2,
2012 ondisk_path, path, sb.st_mode, label_orig, blob,
2013 worktree->base_commit_id, repo,
2014 progress_cb, progress_arg);
2016 free(label_orig);
2017 if (fd2 != -1 && close(fd2) == -1 && err == NULL) {
2018 err = got_error_from_errno("close");
2019 goto done;
2021 if (blob2)
2022 got_object_blob_close(blob2);
2023 if (err)
2024 goto done;
2026 * Do not update timestamps of files with local changes.
2027 * Otherwise, a future status walk would treat them as
2028 * unmodified files again.
2030 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2031 blob->id.sha1, worktree->base_commit_id->sha1,
2032 update_timestamps);
2033 } else if (status == GOT_STATUS_MODE_CHANGE) {
2034 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2035 blob->id.sha1, worktree->base_commit_id->sha1, 0);
2036 } else if (status == GOT_STATUS_DELETE) {
2037 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
2038 if (err)
2039 goto done;
2040 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2041 blob->id.sha1, worktree->base_commit_id->sha1, 0);
2042 if (err)
2043 goto done;
2044 } else {
2045 int is_bad_symlink = 0;
2046 if (S_ISLNK(te->mode)) {
2047 err = install_symlink(&is_bad_symlink, worktree,
2048 ondisk_path, path, blob,
2049 status == GOT_STATUS_MISSING, 0,
2050 status == GOT_STATUS_UNVERSIONED, 0,
2051 repo, progress_cb, progress_arg);
2052 } else {
2053 err = install_blob(worktree, ondisk_path, path,
2054 te->mode, sb.st_mode, blob,
2055 status == GOT_STATUS_MISSING, 0, 0,
2056 status == GOT_STATUS_UNVERSIONED, repo,
2057 progress_cb, progress_arg);
2059 if (err)
2060 goto done;
2062 if (ie) {
2063 err = got_fileindex_entry_update(ie,
2064 worktree->root_fd, path, blob->id.sha1,
2065 worktree->base_commit_id->sha1, 1);
2066 } else {
2067 err = create_fileindex_entry(&ie, fileindex,
2068 worktree->base_commit_id, worktree->root_fd, path,
2069 &blob->id);
2071 if (err)
2072 goto done;
2074 if (is_bad_symlink) {
2075 got_fileindex_entry_filetype_set(ie,
2076 GOT_FILEIDX_MODE_BAD_SYMLINK);
2080 if (fd1 != -1 && close(fd1) == -1 && err == NULL) {
2081 err = got_error_from_errno("close");
2082 goto done;
2084 got_object_blob_close(blob);
2085 done:
2086 free(ondisk_path);
2087 return err;
2090 static const struct got_error *
2091 remove_ondisk_file(const char *root_path, const char *path)
2093 const struct got_error *err = NULL;
2094 char *ondisk_path = NULL, *parent = NULL;
2096 if (asprintf(&ondisk_path, "%s/%s", root_path, path) == -1)
2097 return got_error_from_errno("asprintf");
2099 if (unlink(ondisk_path) == -1) {
2100 if (errno != ENOENT)
2101 err = got_error_from_errno2("unlink", ondisk_path);
2102 } else {
2103 size_t root_len = strlen(root_path);
2104 err = got_path_dirname(&parent, ondisk_path);
2105 if (err)
2106 goto done;
2107 while (got_path_cmp(parent, root_path,
2108 strlen(parent), root_len) != 0) {
2109 free(ondisk_path);
2110 ondisk_path = parent;
2111 parent = NULL;
2112 if (rmdir(ondisk_path) == -1) {
2113 if (errno != ENOTEMPTY)
2114 err = got_error_from_errno2("rmdir",
2115 ondisk_path);
2116 break;
2118 err = got_path_dirname(&parent, ondisk_path);
2119 if (err)
2120 break;
2123 done:
2124 free(ondisk_path);
2125 free(parent);
2126 return err;
2129 static const struct got_error *
2130 delete_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
2131 struct got_fileindex_entry *ie, struct got_repository *repo,
2132 got_worktree_checkout_cb progress_cb, void *progress_arg)
2134 const struct got_error *err = NULL;
2135 unsigned char status;
2136 struct stat sb;
2137 char *ondisk_path;
2139 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE)
2140 return got_error_path(ie->path, GOT_ERR_FILE_STAGED);
2142 if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, ie->path)
2143 == -1)
2144 return got_error_from_errno("asprintf");
2146 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo);
2147 if (err)
2148 goto done;
2150 if (S_ISLNK(sb.st_mode) && status != GOT_STATUS_NO_CHANGE) {
2151 char ondisk_target[PATH_MAX];
2152 ssize_t ondisk_len = readlink(ondisk_path, ondisk_target,
2153 sizeof(ondisk_target));
2154 if (ondisk_len == -1) {
2155 err = got_error_from_errno2("readlink", ondisk_path);
2156 goto done;
2158 ondisk_target[ondisk_len] = '\0';
2159 err = install_symlink_conflict(NULL, worktree->base_commit_id,
2160 NULL, NULL, /* XXX pass common ancestor info? */
2161 ondisk_target, ondisk_path);
2162 if (err)
2163 goto done;
2164 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
2165 ie->path);
2166 goto done;
2169 if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_CONFLICT ||
2170 status == GOT_STATUS_ADD) {
2171 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, ie->path);
2172 if (err)
2173 goto done;
2175 * Preserve the working file and change the deleted blob's
2176 * entry into a schedule-add entry.
2178 err = got_fileindex_entry_update(ie, worktree->root_fd,
2179 ie->path, NULL, NULL, 0);
2180 } else {
2181 err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE, ie->path);
2182 if (err)
2183 goto done;
2184 if (status == GOT_STATUS_NO_CHANGE) {
2185 err = remove_ondisk_file(worktree->root_path, ie->path);
2186 if (err)
2187 goto done;
2189 got_fileindex_entry_remove(fileindex, ie);
2191 done:
2192 free(ondisk_path);
2193 return err;
2196 struct diff_cb_arg {
2197 struct got_fileindex *fileindex;
2198 struct got_worktree *worktree;
2199 struct got_repository *repo;
2200 got_worktree_checkout_cb progress_cb;
2201 void *progress_arg;
2202 got_cancel_cb cancel_cb;
2203 void *cancel_arg;
2206 static const struct got_error *
2207 diff_old_new(void *arg, struct got_fileindex_entry *ie,
2208 struct got_tree_entry *te, const char *parent_path)
2210 struct diff_cb_arg *a = arg;
2212 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
2213 return got_error(GOT_ERR_CANCELLED);
2215 return update_blob(a->worktree, a->fileindex, ie, te,
2216 ie->path, a->repo, a->progress_cb, a->progress_arg);
2219 static const struct got_error *
2220 diff_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path)
2222 struct diff_cb_arg *a = arg;
2224 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
2225 return got_error(GOT_ERR_CANCELLED);
2227 return delete_blob(a->worktree, a->fileindex, ie,
2228 a->repo, a->progress_cb, a->progress_arg);
2231 static const struct got_error *
2232 diff_new(void *arg, struct got_tree_entry *te, const char *parent_path)
2234 struct diff_cb_arg *a = arg;
2235 const struct got_error *err;
2236 char *path;
2238 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
2239 return got_error(GOT_ERR_CANCELLED);
2241 if (got_object_tree_entry_is_submodule(te))
2242 return NULL;
2244 if (asprintf(&path, "%s%s%s", parent_path,
2245 parent_path[0] ? "/" : "", te->name)
2246 == -1)
2247 return got_error_from_errno("asprintf");
2249 if (S_ISDIR(te->mode))
2250 err = add_dir_on_disk(a->worktree, path);
2251 else
2252 err = update_blob(a->worktree, a->fileindex, NULL, te, path,
2253 a->repo, a->progress_cb, a->progress_arg);
2255 free(path);
2256 return err;
2259 const struct got_error *
2260 got_worktree_get_uuid(char **uuidstr, struct got_worktree *worktree)
2262 uint32_t uuid_status;
2264 uuid_to_string(&worktree->uuid, uuidstr, &uuid_status);
2265 if (uuid_status != uuid_s_ok) {
2266 *uuidstr = NULL;
2267 return got_error_uuid(uuid_status, "uuid_to_string");
2270 return NULL;
2273 static const struct got_error *
2274 get_ref_name(char **refname, struct got_worktree *worktree, const char *prefix)
2276 const struct got_error *err = NULL;
2277 char *uuidstr = NULL;
2279 *refname = NULL;
2281 err = got_worktree_get_uuid(&uuidstr, worktree);
2282 if (err)
2283 return err;
2285 if (asprintf(refname, "%s-%s", prefix, uuidstr) == -1) {
2286 err = got_error_from_errno("asprintf");
2287 *refname = NULL;
2289 free(uuidstr);
2290 return err;
2293 const struct got_error *
2294 got_worktree_get_logmsg_ref_name(char **refname, struct got_worktree *worktree,
2295 const char *prefix)
2297 return get_ref_name(refname, worktree, prefix);
2300 const struct got_error *
2301 got_worktree_get_base_ref_name(char **refname, struct got_worktree *worktree)
2303 return get_ref_name(refname, worktree, GOT_WORKTREE_BASE_REF_PREFIX);
2306 static const struct got_error *
2307 get_rebase_tmp_ref_name(char **refname, struct got_worktree *worktree)
2309 return get_ref_name(refname, worktree,
2310 GOT_WORKTREE_REBASE_TMP_REF_PREFIX);
2313 static const struct got_error *
2314 get_newbase_symref_name(char **refname, struct got_worktree *worktree)
2316 return get_ref_name(refname, worktree, GOT_WORKTREE_NEWBASE_REF_PREFIX);
2319 static const struct got_error *
2320 get_rebase_branch_symref_name(char **refname, struct got_worktree *worktree)
2322 return get_ref_name(refname, worktree,
2323 GOT_WORKTREE_REBASE_BRANCH_REF_PREFIX);
2326 static const struct got_error *
2327 get_rebase_commit_ref_name(char **refname, struct got_worktree *worktree)
2329 return get_ref_name(refname, worktree,
2330 GOT_WORKTREE_REBASE_COMMIT_REF_PREFIX);
2333 static const struct got_error *
2334 get_histedit_tmp_ref_name(char **refname, struct got_worktree *worktree)
2336 return get_ref_name(refname, worktree,
2337 GOT_WORKTREE_HISTEDIT_TMP_REF_PREFIX);
2340 static const struct got_error *
2341 get_histedit_branch_symref_name(char **refname, struct got_worktree *worktree)
2343 return get_ref_name(refname, worktree,
2344 GOT_WORKTREE_HISTEDIT_BRANCH_REF_PREFIX);
2347 static const struct got_error *
2348 get_histedit_base_commit_ref_name(char **refname, struct got_worktree *worktree)
2350 return get_ref_name(refname, worktree,
2351 GOT_WORKTREE_HISTEDIT_BASE_COMMIT_REF_PREFIX);
2354 static const struct got_error *
2355 get_histedit_commit_ref_name(char **refname, struct got_worktree *worktree)
2357 return get_ref_name(refname, worktree,
2358 GOT_WORKTREE_HISTEDIT_COMMIT_REF_PREFIX);
2361 const struct got_error *
2362 got_worktree_get_histedit_script_path(char **path,
2363 struct got_worktree *worktree)
2365 if (asprintf(path, "%s/%s/%s", worktree->root_path,
2366 GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_HISTEDIT_SCRIPT) == -1) {
2367 *path = NULL;
2368 return got_error_from_errno("asprintf");
2370 return NULL;
2373 static const struct got_error *
2374 get_merge_branch_ref_name(char **refname, struct got_worktree *worktree)
2376 return get_ref_name(refname, worktree,
2377 GOT_WORKTREE_MERGE_BRANCH_REF_PREFIX);
2380 static const struct got_error *
2381 get_merge_commit_ref_name(char **refname, struct got_worktree *worktree)
2383 return get_ref_name(refname, worktree,
2384 GOT_WORKTREE_MERGE_COMMIT_REF_PREFIX);
2388 * Prevent Git's garbage collector from deleting our base commit by
2389 * setting a reference to our base commit's ID.
2391 static const struct got_error *
2392 ref_base_commit(struct got_worktree *worktree, struct got_repository *repo)
2394 const struct got_error *err = NULL;
2395 struct got_reference *ref = NULL;
2396 char *refname;
2398 err = got_worktree_get_base_ref_name(&refname, worktree);
2399 if (err)
2400 return err;
2402 err = got_ref_alloc(&ref, refname, worktree->base_commit_id);
2403 if (err)
2404 goto done;
2406 err = got_ref_write(ref, repo);
2407 done:
2408 free(refname);
2409 if (ref)
2410 got_ref_close(ref);
2411 return err;
2414 static const struct got_error *
2415 get_fileindex_path(char **fileindex_path, struct got_worktree *worktree)
2417 const struct got_error *err = NULL;
2419 if (asprintf(fileindex_path, "%s/%s/%s", worktree->root_path,
2420 GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_FILE_INDEX) == -1) {
2421 err = got_error_from_errno("asprintf");
2422 *fileindex_path = NULL;
2424 return err;
2428 static const struct got_error *
2429 open_fileindex(struct got_fileindex **fileindex, char **fileindex_path,
2430 struct got_worktree *worktree)
2432 const struct got_error *err = NULL;
2433 FILE *index = NULL;
2435 *fileindex_path = NULL;
2436 *fileindex = got_fileindex_alloc();
2437 if (*fileindex == NULL)
2438 return got_error_from_errno("got_fileindex_alloc");
2440 err = get_fileindex_path(fileindex_path, worktree);
2441 if (err)
2442 goto done;
2444 index = fopen(*fileindex_path, "rbe");
2445 if (index == NULL) {
2446 if (errno != ENOENT)
2447 err = got_error_from_errno2("fopen", *fileindex_path);
2448 } else {
2449 err = got_fileindex_read(*fileindex, index);
2450 if (fclose(index) == EOF && err == NULL)
2451 err = got_error_from_errno("fclose");
2453 done:
2454 if (err) {
2455 free(*fileindex_path);
2456 *fileindex_path = NULL;
2457 got_fileindex_free(*fileindex);
2458 *fileindex = NULL;
2460 return err;
2463 struct bump_base_commit_id_arg {
2464 struct got_object_id *base_commit_id;
2465 const char *path;
2466 size_t path_len;
2467 const char *entry_name;
2468 got_worktree_checkout_cb progress_cb;
2469 void *progress_arg;
2472 static const struct got_error *
2473 bump_base_commit_id(void *arg, struct got_fileindex_entry *ie)
2475 const struct got_error *err;
2476 struct bump_base_commit_id_arg *a = arg;
2478 if (a->entry_name) {
2479 if (strcmp(ie->path, a->path) != 0)
2480 return NULL;
2481 } else if (!got_path_is_child(ie->path, a->path, a->path_len))
2482 return NULL;
2484 if (got_fileindex_entry_was_skipped(ie))
2485 return NULL;
2487 if (memcmp(ie->commit_sha1, a->base_commit_id->sha1,
2488 SHA1_DIGEST_LENGTH) == 0)
2489 return NULL;
2491 if (a->progress_cb) {
2492 err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_BUMP_BASE,
2493 ie->path);
2494 if (err)
2495 return err;
2497 memcpy(ie->commit_sha1, a->base_commit_id->sha1, SHA1_DIGEST_LENGTH);
2498 return NULL;
2501 /* Bump base commit ID of all files within an updated part of the work tree. */
2502 static const struct got_error *
2503 bump_base_commit_id_everywhere(struct got_worktree *worktree,
2504 struct got_fileindex *fileindex,
2505 got_worktree_checkout_cb progress_cb, void *progress_arg)
2507 struct bump_base_commit_id_arg bbc_arg;
2509 bbc_arg.base_commit_id = worktree->base_commit_id;
2510 bbc_arg.entry_name = NULL;
2511 bbc_arg.path = "";
2512 bbc_arg.path_len = 0;
2513 bbc_arg.progress_cb = progress_cb;
2514 bbc_arg.progress_arg = progress_arg;
2516 return got_fileindex_for_each_entry_safe(fileindex,
2517 bump_base_commit_id, &bbc_arg);
2520 static const struct got_error *
2521 sync_fileindex(struct got_fileindex *fileindex, const char *fileindex_path)
2523 const struct got_error *err = NULL;
2524 char *new_fileindex_path = NULL;
2525 FILE *new_index = NULL;
2526 struct timespec timeout;
2528 err = got_opentemp_named(&new_fileindex_path, &new_index,
2529 fileindex_path, "");
2530 if (err)
2531 goto done;
2533 err = got_fileindex_write(fileindex, new_index);
2534 if (err)
2535 goto done;
2537 if (rename(new_fileindex_path, fileindex_path) != 0) {
2538 err = got_error_from_errno3("rename", new_fileindex_path,
2539 fileindex_path);
2540 unlink(new_fileindex_path);
2544 * Sleep for a short amount of time to ensure that files modified after
2545 * this program exits have a different time stamp from the one which
2546 * was recorded in the file index.
2548 timeout.tv_sec = 0;
2549 timeout.tv_nsec = 1;
2550 nanosleep(&timeout, NULL);
2551 done:
2552 if (new_index)
2553 fclose(new_index);
2554 free(new_fileindex_path);
2555 return err;
2558 static const struct got_error *
2559 find_tree_entry_for_checkout(int *entry_type, char **tree_relpath,
2560 struct got_object_id **tree_id, const char *wt_relpath,
2561 struct got_commit_object *base_commit, struct got_worktree *worktree,
2562 struct got_repository *repo)
2564 const struct got_error *err = NULL;
2565 struct got_object_id *id = NULL;
2566 char *in_repo_path = NULL;
2567 int is_root_wt = got_path_is_root_dir(worktree->path_prefix);
2569 *entry_type = GOT_OBJ_TYPE_ANY;
2570 *tree_relpath = NULL;
2571 *tree_id = NULL;
2573 if (wt_relpath[0] == '\0') {
2574 /* Check out all files within the work tree. */
2575 *entry_type = GOT_OBJ_TYPE_TREE;
2576 *tree_relpath = strdup("");
2577 if (*tree_relpath == NULL) {
2578 err = got_error_from_errno("strdup");
2579 goto done;
2581 err = got_object_id_by_path(tree_id, repo, base_commit,
2582 worktree->path_prefix);
2583 if (err)
2584 goto done;
2585 return NULL;
2588 /* Check out a subset of files in the work tree. */
2590 if (asprintf(&in_repo_path, "%s%s%s", worktree->path_prefix,
2591 is_root_wt ? "" : "/", wt_relpath) == -1) {
2592 err = got_error_from_errno("asprintf");
2593 goto done;
2596 err = got_object_id_by_path(&id, repo, base_commit, in_repo_path);
2597 if (err)
2598 goto done;
2600 free(in_repo_path);
2601 in_repo_path = NULL;
2603 err = got_object_get_type(entry_type, repo, id);
2604 if (err)
2605 goto done;
2607 if (*entry_type == GOT_OBJ_TYPE_BLOB) {
2608 /* Check out a single file. */
2609 if (strchr(wt_relpath, '/') == NULL) {
2610 /* Check out a single file in work tree's root dir. */
2611 in_repo_path = strdup(worktree->path_prefix);
2612 if (in_repo_path == NULL) {
2613 err = got_error_from_errno("strdup");
2614 goto done;
2616 *tree_relpath = strdup("");
2617 if (*tree_relpath == NULL) {
2618 err = got_error_from_errno("strdup");
2619 goto done;
2621 } else {
2622 /* Check out a single file in a subdirectory. */
2623 err = got_path_dirname(tree_relpath, wt_relpath);
2624 if (err)
2625 return err;
2626 if (asprintf(&in_repo_path, "%s%s%s",
2627 worktree->path_prefix, is_root_wt ? "" : "/",
2628 *tree_relpath) == -1) {
2629 err = got_error_from_errno("asprintf");
2630 goto done;
2633 err = got_object_id_by_path(tree_id, repo,
2634 base_commit, in_repo_path);
2635 } else {
2636 /* Check out all files within a subdirectory. */
2637 *tree_id = got_object_id_dup(id);
2638 if (*tree_id == NULL) {
2639 err = got_error_from_errno("got_object_id_dup");
2640 goto done;
2642 *tree_relpath = strdup(wt_relpath);
2643 if (*tree_relpath == NULL) {
2644 err = got_error_from_errno("strdup");
2645 goto done;
2648 done:
2649 free(id);
2650 free(in_repo_path);
2651 if (err) {
2652 *entry_type = GOT_OBJ_TYPE_ANY;
2653 free(*tree_relpath);
2654 *tree_relpath = NULL;
2655 free(*tree_id);
2656 *tree_id = NULL;
2658 return err;
2661 static const struct got_error *
2662 checkout_files(struct got_worktree *worktree, struct got_fileindex *fileindex,
2663 const char *relpath, struct got_object_id *tree_id, const char *entry_name,
2664 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
2665 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
2667 const struct got_error *err = NULL;
2668 struct got_commit_object *commit = NULL;
2669 struct got_tree_object *tree = NULL;
2670 struct got_fileindex_diff_tree_cb diff_cb;
2671 struct diff_cb_arg arg;
2673 err = ref_base_commit(worktree, repo);
2674 if (err) {
2675 if (!(err->code == GOT_ERR_ERRNO &&
2676 (errno == EACCES || errno == EROFS)))
2677 goto done;
2678 err = (*progress_cb)(progress_arg,
2679 GOT_STATUS_BASE_REF_ERR, worktree->root_path);
2680 if (err)
2681 return err;
2684 err = got_object_open_as_commit(&commit, repo,
2685 worktree->base_commit_id);
2686 if (err)
2687 goto done;
2689 err = got_object_open_as_tree(&tree, repo, tree_id);
2690 if (err)
2691 goto done;
2693 if (entry_name &&
2694 got_object_tree_find_entry(tree, entry_name) == NULL) {
2695 err = got_error_path(entry_name, GOT_ERR_NO_TREE_ENTRY);
2696 goto done;
2699 diff_cb.diff_old_new = diff_old_new;
2700 diff_cb.diff_old = diff_old;
2701 diff_cb.diff_new = diff_new;
2702 arg.fileindex = fileindex;
2703 arg.worktree = worktree;
2704 arg.repo = repo;
2705 arg.progress_cb = progress_cb;
2706 arg.progress_arg = progress_arg;
2707 arg.cancel_cb = cancel_cb;
2708 arg.cancel_arg = cancel_arg;
2709 err = got_fileindex_diff_tree(fileindex, tree, relpath,
2710 entry_name, repo, &diff_cb, &arg);
2711 done:
2712 if (tree)
2713 got_object_tree_close(tree);
2714 if (commit)
2715 got_object_commit_close(commit);
2716 return err;
2719 const struct got_error *
2720 got_worktree_checkout_files(struct got_worktree *worktree,
2721 struct got_pathlist_head *paths, struct got_repository *repo,
2722 got_worktree_checkout_cb progress_cb, void *progress_arg,
2723 got_cancel_cb cancel_cb, void *cancel_arg)
2725 const struct got_error *err = NULL, *sync_err, *unlockerr;
2726 struct got_commit_object *commit = NULL;
2727 struct got_tree_object *tree = NULL;
2728 struct got_fileindex *fileindex = NULL;
2729 char *fileindex_path = NULL;
2730 struct got_pathlist_entry *pe;
2731 struct tree_path_data {
2732 STAILQ_ENTRY(tree_path_data) entry;
2733 struct got_object_id *tree_id;
2734 int entry_type;
2735 char *relpath;
2736 char *entry_name;
2737 } *tpd = NULL;
2738 STAILQ_HEAD(tree_paths, tree_path_data) tree_paths;
2740 STAILQ_INIT(&tree_paths);
2742 err = lock_worktree(worktree, LOCK_EX);
2743 if (err)
2744 return err;
2746 err = got_object_open_as_commit(&commit, repo,
2747 worktree->base_commit_id);
2748 if (err)
2749 goto done;
2751 /* Map all specified paths to in-repository trees. */
2752 TAILQ_FOREACH(pe, paths, entry) {
2753 tpd = malloc(sizeof(*tpd));
2754 if (tpd == NULL) {
2755 err = got_error_from_errno("malloc");
2756 goto done;
2759 err = find_tree_entry_for_checkout(&tpd->entry_type,
2760 &tpd->relpath, &tpd->tree_id, pe->path, commit,
2761 worktree, repo);
2762 if (err) {
2763 free(tpd);
2764 goto done;
2767 if (tpd->entry_type == GOT_OBJ_TYPE_BLOB) {
2768 err = got_path_basename(&tpd->entry_name, pe->path);
2769 if (err) {
2770 free(tpd->relpath);
2771 free(tpd->tree_id);
2772 free(tpd);
2773 goto done;
2775 } else
2776 tpd->entry_name = NULL;
2778 STAILQ_INSERT_TAIL(&tree_paths, tpd, entry);
2782 * Read the file index.
2783 * Checking out files is supposed to be an idempotent operation.
2784 * If the on-disk file index is incomplete we will try to complete it.
2786 err = open_fileindex(&fileindex, &fileindex_path, worktree);
2787 if (err)
2788 goto done;
2790 tpd = STAILQ_FIRST(&tree_paths);
2791 TAILQ_FOREACH(pe, paths, entry) {
2792 struct bump_base_commit_id_arg bbc_arg;
2794 err = checkout_files(worktree, fileindex, tpd->relpath,
2795 tpd->tree_id, tpd->entry_name, repo,
2796 progress_cb, progress_arg, cancel_cb, cancel_arg);
2797 if (err)
2798 break;
2800 bbc_arg.base_commit_id = worktree->base_commit_id;
2801 bbc_arg.entry_name = tpd->entry_name;
2802 bbc_arg.path = pe->path;
2803 bbc_arg.path_len = pe->path_len;
2804 bbc_arg.progress_cb = progress_cb;
2805 bbc_arg.progress_arg = progress_arg;
2806 err = got_fileindex_for_each_entry_safe(fileindex,
2807 bump_base_commit_id, &bbc_arg);
2808 if (err)
2809 break;
2811 tpd = STAILQ_NEXT(tpd, entry);
2813 sync_err = sync_fileindex(fileindex, fileindex_path);
2814 if (sync_err && err == NULL)
2815 err = sync_err;
2816 done:
2817 free(fileindex_path);
2818 if (tree)
2819 got_object_tree_close(tree);
2820 if (commit)
2821 got_object_commit_close(commit);
2822 if (fileindex)
2823 got_fileindex_free(fileindex);
2824 while (!STAILQ_EMPTY(&tree_paths)) {
2825 tpd = STAILQ_FIRST(&tree_paths);
2826 STAILQ_REMOVE_HEAD(&tree_paths, entry);
2827 free(tpd->relpath);
2828 free(tpd->tree_id);
2829 free(tpd);
2831 unlockerr = lock_worktree(worktree, LOCK_SH);
2832 if (unlockerr && err == NULL)
2833 err = unlockerr;
2834 return err;
2837 struct merge_file_cb_arg {
2838 struct got_worktree *worktree;
2839 struct got_fileindex *fileindex;
2840 got_worktree_checkout_cb progress_cb;
2841 void *progress_arg;
2842 got_cancel_cb cancel_cb;
2843 void *cancel_arg;
2844 const char *label_orig;
2845 struct got_object_id *commit_id2;
2846 int allow_bad_symlinks;
2849 static const struct got_error *
2850 merge_file_cb(void *arg, struct got_blob_object *blob1,
2851 struct got_blob_object *blob2, FILE *f1, FILE *f2,
2852 struct got_object_id *id1, struct got_object_id *id2,
2853 const char *path1, const char *path2,
2854 mode_t mode1, mode_t mode2, struct got_repository *repo)
2856 static const struct got_error *err = NULL;
2857 struct merge_file_cb_arg *a = arg;
2858 struct got_fileindex_entry *ie;
2859 char *ondisk_path = NULL;
2860 struct stat sb;
2861 unsigned char status;
2862 int local_changes_subsumed;
2863 FILE *f_orig = NULL, *f_deriv = NULL, *f_deriv2 = NULL;
2864 char *id_str = NULL, *label_deriv2 = NULL;
2866 if (blob1 && blob2) {
2867 ie = got_fileindex_entry_get(a->fileindex, path2,
2868 strlen(path2));
2869 if (ie == NULL)
2870 return (*a->progress_cb)(a->progress_arg,
2871 GOT_STATUS_MISSING, path2);
2873 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
2874 path2) == -1)
2875 return got_error_from_errno("asprintf");
2877 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
2878 repo);
2879 if (err)
2880 goto done;
2882 if (status == GOT_STATUS_DELETE) {
2883 err = (*a->progress_cb)(a->progress_arg,
2884 GOT_STATUS_MERGE, path2);
2885 goto done;
2887 if (status != GOT_STATUS_NO_CHANGE &&
2888 status != GOT_STATUS_MODIFY &&
2889 status != GOT_STATUS_CONFLICT &&
2890 status != GOT_STATUS_ADD) {
2891 err = (*a->progress_cb)(a->progress_arg, status, path2);
2892 goto done;
2895 if (S_ISLNK(mode1) && S_ISLNK(mode2)) {
2896 char *link_target2;
2897 err = got_object_blob_read_to_str(&link_target2, blob2);
2898 if (err)
2899 goto done;
2900 err = merge_symlink(a->worktree, blob1, ondisk_path,
2901 path2, a->label_orig, link_target2, a->commit_id2,
2902 repo, a->progress_cb, a->progress_arg);
2903 free(link_target2);
2904 } else {
2905 int fd;
2907 f_orig = got_opentemp();
2908 if (f_orig == NULL) {
2909 err = got_error_from_errno("got_opentemp");
2910 goto done;
2912 err = got_object_blob_dump_to_file(NULL, NULL, NULL,
2913 f_orig, blob1);
2914 if (err)
2915 goto done;
2917 f_deriv2 = got_opentemp();
2918 if (f_deriv2 == NULL)
2919 goto done;
2920 err = got_object_blob_dump_to_file(NULL, NULL, NULL,
2921 f_deriv2, blob2);
2922 if (err)
2923 goto done;
2925 fd = open(ondisk_path,
2926 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
2927 if (fd == -1) {
2928 err = got_error_from_errno2("open",
2929 ondisk_path);
2930 goto done;
2932 f_deriv = fdopen(fd, "r");
2933 if (f_deriv == NULL) {
2934 err = got_error_from_errno2("fdopen",
2935 ondisk_path);
2936 close(fd);
2937 goto done;
2939 err = got_object_id_str(&id_str, a->commit_id2);
2940 if (err)
2941 goto done;
2942 if (asprintf(&label_deriv2, "%s: commit %s",
2943 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
2944 err = got_error_from_errno("asprintf");
2945 goto done;
2947 err = merge_file(&local_changes_subsumed, a->worktree,
2948 f_orig, f_deriv, f_deriv2, ondisk_path, path2,
2949 mode2, a->label_orig, NULL, label_deriv2,
2950 GOT_DIFF_ALGORITHM_PATIENCE, repo,
2951 a->progress_cb, a->progress_arg);
2953 } else if (blob1) {
2954 ie = got_fileindex_entry_get(a->fileindex, path1,
2955 strlen(path1));
2956 if (ie == NULL)
2957 return (*a->progress_cb)(a->progress_arg,
2958 GOT_STATUS_MISSING, path1);
2960 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
2961 path1) == -1)
2962 return got_error_from_errno("asprintf");
2964 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
2965 repo);
2966 if (err)
2967 goto done;
2969 switch (status) {
2970 case GOT_STATUS_NO_CHANGE:
2971 err = (*a->progress_cb)(a->progress_arg,
2972 GOT_STATUS_DELETE, path1);
2973 if (err)
2974 goto done;
2975 err = remove_ondisk_file(a->worktree->root_path, path1);
2976 if (err)
2977 goto done;
2978 if (ie)
2979 got_fileindex_entry_mark_deleted_from_disk(ie);
2980 break;
2981 case GOT_STATUS_DELETE:
2982 case GOT_STATUS_MISSING:
2983 err = (*a->progress_cb)(a->progress_arg,
2984 GOT_STATUS_DELETE, path1);
2985 if (err)
2986 goto done;
2987 if (ie)
2988 got_fileindex_entry_mark_deleted_from_disk(ie);
2989 break;
2990 case GOT_STATUS_ADD: {
2991 struct got_object_id *id;
2992 FILE *blob1_f;
2993 off_t blob1_size;
2995 * Delete the added file only if its content already
2996 * exists in the repository.
2998 err = got_object_blob_file_create(&id, &blob1_f,
2999 &blob1_size, path1);
3000 if (err)
3001 goto done;
3002 if (got_object_id_cmp(id, id1) == 0) {
3003 err = (*a->progress_cb)(a->progress_arg,
3004 GOT_STATUS_DELETE, path1);
3005 if (err)
3006 goto done;
3007 err = remove_ondisk_file(a->worktree->root_path,
3008 path1);
3009 if (err)
3010 goto done;
3011 if (ie)
3012 got_fileindex_entry_remove(a->fileindex,
3013 ie);
3014 } else {
3015 err = (*a->progress_cb)(a->progress_arg,
3016 GOT_STATUS_CANNOT_DELETE, path1);
3018 if (fclose(blob1_f) == EOF && err == NULL)
3019 err = got_error_from_errno("fclose");
3020 free(id);
3021 if (err)
3022 goto done;
3023 break;
3025 case GOT_STATUS_MODIFY:
3026 case GOT_STATUS_CONFLICT:
3027 err = (*a->progress_cb)(a->progress_arg,
3028 GOT_STATUS_CANNOT_DELETE, path1);
3029 if (err)
3030 goto done;
3031 break;
3032 case GOT_STATUS_OBSTRUCTED:
3033 err = (*a->progress_cb)(a->progress_arg, status, path1);
3034 if (err)
3035 goto done;
3036 break;
3037 default:
3038 break;
3040 } else if (blob2) {
3041 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
3042 path2) == -1)
3043 return got_error_from_errno("asprintf");
3044 ie = got_fileindex_entry_get(a->fileindex, path2,
3045 strlen(path2));
3046 if (ie) {
3047 err = get_file_status(&status, &sb, ie, ondisk_path,
3048 -1, NULL, repo);
3049 if (err)
3050 goto done;
3051 if (status != GOT_STATUS_NO_CHANGE &&
3052 status != GOT_STATUS_MODIFY &&
3053 status != GOT_STATUS_CONFLICT &&
3054 status != GOT_STATUS_ADD) {
3055 err = (*a->progress_cb)(a->progress_arg,
3056 status, path2);
3057 goto done;
3059 if (S_ISLNK(mode2) && S_ISLNK(sb.st_mode)) {
3060 char *link_target2;
3061 err = got_object_blob_read_to_str(&link_target2,
3062 blob2);
3063 if (err)
3064 goto done;
3065 err = merge_symlink(a->worktree, NULL,
3066 ondisk_path, path2, a->label_orig,
3067 link_target2, a->commit_id2, repo,
3068 a->progress_cb, a->progress_arg);
3069 free(link_target2);
3070 } else if (S_ISREG(sb.st_mode)) {
3071 err = merge_blob(&local_changes_subsumed,
3072 a->worktree, NULL, ondisk_path, path2,
3073 sb.st_mode, a->label_orig, blob2,
3074 a->commit_id2, repo, a->progress_cb,
3075 a->progress_arg);
3076 } else {
3077 err = got_error_path(ondisk_path,
3078 GOT_ERR_FILE_OBSTRUCTED);
3080 if (err)
3081 goto done;
3082 if (status == GOT_STATUS_DELETE) {
3083 err = got_fileindex_entry_update(ie,
3084 a->worktree->root_fd, path2, blob2->id.sha1,
3085 a->worktree->base_commit_id->sha1, 0);
3086 if (err)
3087 goto done;
3089 } else {
3090 int is_bad_symlink = 0;
3091 sb.st_mode = GOT_DEFAULT_FILE_MODE;
3092 if (S_ISLNK(mode2)) {
3093 err = install_symlink(&is_bad_symlink,
3094 a->worktree, ondisk_path, path2, blob2, 0,
3095 0, 1, a->allow_bad_symlinks, repo,
3096 a->progress_cb, a->progress_arg);
3097 } else {
3098 err = install_blob(a->worktree, ondisk_path, path2,
3099 mode2, sb.st_mode, blob2, 0, 0, 0, 1, repo,
3100 a->progress_cb, a->progress_arg);
3102 if (err)
3103 goto done;
3104 err = got_fileindex_entry_alloc(&ie, path2);
3105 if (err)
3106 goto done;
3107 err = got_fileindex_entry_update(ie,
3108 a->worktree->root_fd, path2, NULL, NULL, 1);
3109 if (err) {
3110 got_fileindex_entry_free(ie);
3111 goto done;
3113 err = got_fileindex_entry_add(a->fileindex, ie);
3114 if (err) {
3115 got_fileindex_entry_free(ie);
3116 goto done;
3118 if (is_bad_symlink) {
3119 got_fileindex_entry_filetype_set(ie,
3120 GOT_FILEIDX_MODE_BAD_SYMLINK);
3124 done:
3125 if (f_orig && fclose(f_orig) == EOF && err == NULL)
3126 err = got_error_from_errno("fclose");
3127 if (f_deriv && fclose(f_deriv) == EOF && err == NULL)
3128 err = got_error_from_errno("fclose");
3129 if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL)
3130 err = got_error_from_errno("fclose");
3131 free(id_str);
3132 free(label_deriv2);
3133 free(ondisk_path);
3134 return err;
3137 static const struct got_error *
3138 check_mixed_commits(void *arg, struct got_fileindex_entry *ie)
3140 struct got_worktree *worktree = arg;
3142 /* Reject merges into a work tree with mixed base commits. */
3143 if (got_fileindex_entry_has_commit(ie) &&
3144 memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
3145 SHA1_DIGEST_LENGTH) != 0)
3146 return got_error(GOT_ERR_MIXED_COMMITS);
3148 return NULL;
3151 struct check_merge_conflicts_arg {
3152 struct got_worktree *worktree;
3153 struct got_fileindex *fileindex;
3154 struct got_repository *repo;
3157 static const struct got_error *
3158 check_merge_conflicts(void *arg, struct got_blob_object *blob1,
3159 struct got_blob_object *blob2, FILE *f1, FILE *f2,
3160 struct got_object_id *id1, struct got_object_id *id2,
3161 const char *path1, const char *path2,
3162 mode_t mode1, mode_t mode2, struct got_repository *repo)
3164 const struct got_error *err = NULL;
3165 struct check_merge_conflicts_arg *a = arg;
3166 unsigned char status;
3167 struct stat sb;
3168 struct got_fileindex_entry *ie;
3169 const char *path = path2 ? path2 : path1;
3170 struct got_object_id *id = id2 ? id2 : id1;
3171 char *ondisk_path;
3173 if (id == NULL)
3174 return NULL;
3176 ie = got_fileindex_entry_get(a->fileindex, path, strlen(path));
3177 if (ie == NULL)
3178 return NULL;
3180 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path)
3181 == -1)
3182 return got_error_from_errno("asprintf");
3184 /* Reject merges into a work tree with conflicted files. */
3185 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
3186 free(ondisk_path);
3187 if (err)
3188 return err;
3189 if (status == GOT_STATUS_CONFLICT)
3190 return got_error(GOT_ERR_CONFLICTS);
3192 return NULL;
3195 static const struct got_error *
3196 merge_files(struct got_worktree *worktree, struct got_fileindex *fileindex,
3197 const char *fileindex_path, struct got_object_id *commit_id1,
3198 struct got_object_id *commit_id2, struct got_repository *repo,
3199 got_worktree_checkout_cb progress_cb, void *progress_arg,
3200 got_cancel_cb cancel_cb, void *cancel_arg)
3202 const struct got_error *err = NULL, *sync_err;
3203 struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
3204 struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3205 struct got_commit_object *commit1 = NULL, *commit2 = NULL;
3206 struct check_merge_conflicts_arg cmc_arg;
3207 struct merge_file_cb_arg arg;
3208 char *label_orig = NULL;
3209 FILE *f1 = NULL, *f2 = NULL;
3210 int fd1 = -1, fd2 = -1;
3212 if (commit_id1) {
3213 err = got_object_open_as_commit(&commit1, repo, commit_id1);
3214 if (err)
3215 goto done;
3216 err = got_object_id_by_path(&tree_id1, repo, commit1,
3217 worktree->path_prefix);
3218 if (err && err->code != GOT_ERR_NO_TREE_ENTRY)
3219 goto done;
3221 if (tree_id1) {
3222 char *id_str;
3224 err = got_object_open_as_tree(&tree1, repo, tree_id1);
3225 if (err)
3226 goto done;
3228 err = got_object_id_str(&id_str, commit_id1);
3229 if (err)
3230 goto done;
3232 if (asprintf(&label_orig, "%s: commit %s",
3233 GOT_MERGE_LABEL_BASE, id_str) == -1) {
3234 err = got_error_from_errno("asprintf");
3235 free(id_str);
3236 goto done;
3238 free(id_str);
3240 f1 = got_opentemp();
3241 if (f1 == NULL) {
3242 err = got_error_from_errno("got_opentemp");
3243 goto done;
3247 err = got_object_open_as_commit(&commit2, repo, commit_id2);
3248 if (err)
3249 goto done;
3251 err = got_object_id_by_path(&tree_id2, repo, commit2,
3252 worktree->path_prefix);
3253 if (err)
3254 goto done;
3256 err = got_object_open_as_tree(&tree2, repo, tree_id2);
3257 if (err)
3258 goto done;
3260 f2 = got_opentemp();
3261 if (f2 == NULL) {
3262 err = got_error_from_errno("got_opentemp");
3263 goto done;
3266 fd1 = got_opentempfd();
3267 if (fd1 == -1) {
3268 err = got_error_from_errno("got_opentempfd");
3269 goto done;
3272 fd2 = got_opentempfd();
3273 if (fd2 == -1) {
3274 err = got_error_from_errno("got_opentempfd");
3275 goto done;
3278 cmc_arg.worktree = worktree;
3279 cmc_arg.fileindex = fileindex;
3280 cmc_arg.repo = repo;
3281 err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo,
3282 check_merge_conflicts, &cmc_arg, 0);
3283 if (err)
3284 goto done;
3286 arg.worktree = worktree;
3287 arg.fileindex = fileindex;
3288 arg.progress_cb = progress_cb;
3289 arg.progress_arg = progress_arg;
3290 arg.cancel_cb = cancel_cb;
3291 arg.cancel_arg = cancel_arg;
3292 arg.label_orig = label_orig;
3293 arg.commit_id2 = commit_id2;
3294 arg.allow_bad_symlinks = 1; /* preserve bad symlinks across merges */
3295 err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo,
3296 merge_file_cb, &arg, 1);
3297 sync_err = sync_fileindex(fileindex, fileindex_path);
3298 if (sync_err && err == NULL)
3299 err = sync_err;
3300 done:
3301 if (commit1)
3302 got_object_commit_close(commit1);
3303 if (commit2)
3304 got_object_commit_close(commit2);
3305 if (tree1)
3306 got_object_tree_close(tree1);
3307 if (tree2)
3308 got_object_tree_close(tree2);
3309 if (f1 && fclose(f1) == EOF && err == NULL)
3310 err = got_error_from_errno("fclose");
3311 if (f2 && fclose(f2) == EOF && err == NULL)
3312 err = got_error_from_errno("fclose");
3313 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3314 err = got_error_from_errno("close");
3315 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3316 err = got_error_from_errno("close");
3317 free(label_orig);
3318 return err;
3321 const struct got_error *
3322 got_worktree_merge_files(struct got_worktree *worktree,
3323 struct got_object_id *commit_id1, struct got_object_id *commit_id2,
3324 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
3325 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
3327 const struct got_error *err, *unlockerr;
3328 char *fileindex_path = NULL;
3329 struct got_fileindex *fileindex = NULL;
3331 err = lock_worktree(worktree, LOCK_EX);
3332 if (err)
3333 return err;
3335 err = open_fileindex(&fileindex, &fileindex_path, worktree);
3336 if (err)
3337 goto done;
3339 err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits,
3340 worktree);
3341 if (err)
3342 goto done;
3344 err = merge_files(worktree, fileindex, fileindex_path, commit_id1,
3345 commit_id2, repo, progress_cb, progress_arg,
3346 cancel_cb, cancel_arg);
3347 done:
3348 if (fileindex)
3349 got_fileindex_free(fileindex);
3350 free(fileindex_path);
3351 unlockerr = lock_worktree(worktree, LOCK_SH);
3352 if (unlockerr && err == NULL)
3353 err = unlockerr;
3354 return err;
3357 struct diff_dir_cb_arg {
3358 struct got_fileindex *fileindex;
3359 struct got_worktree *worktree;
3360 const char *status_path;
3361 size_t status_path_len;
3362 struct got_repository *repo;
3363 got_worktree_status_cb status_cb;
3364 void *status_arg;
3365 got_cancel_cb cancel_cb;
3366 void *cancel_arg;
3367 /* A pathlist containing per-directory pathlists of ignore patterns. */
3368 struct got_pathlist_head *ignores;
3369 int report_unchanged;
3370 int no_ignores;
3373 static const struct got_error *
3374 report_file_status(struct got_fileindex_entry *ie, const char *abspath,
3375 int dirfd, const char *de_name,
3376 got_worktree_status_cb status_cb, void *status_arg,
3377 struct got_repository *repo, int report_unchanged)
3379 const struct got_error *err = NULL;
3380 unsigned char status = GOT_STATUS_NO_CHANGE;
3381 unsigned char staged_status;
3382 struct stat sb;
3383 struct got_object_id blob_id, commit_id, staged_blob_id;
3384 struct got_object_id *blob_idp = NULL, *commit_idp = NULL;
3385 struct got_object_id *staged_blob_idp = NULL;
3387 staged_status = get_staged_status(ie);
3388 err = get_file_status(&status, &sb, ie, abspath, dirfd, de_name, repo);
3389 if (err)
3390 return err;
3392 if (status == GOT_STATUS_NO_CHANGE &&
3393 staged_status == GOT_STATUS_NO_CHANGE && !report_unchanged)
3394 return NULL;
3396 if (got_fileindex_entry_has_blob(ie))
3397 blob_idp = got_fileindex_entry_get_blob_id(&blob_id, ie);
3398 if (got_fileindex_entry_has_commit(ie))
3399 commit_idp = got_fileindex_entry_get_commit_id(&commit_id, ie);
3400 if (staged_status == GOT_STATUS_ADD ||
3401 staged_status == GOT_STATUS_MODIFY) {
3402 staged_blob_idp = got_fileindex_entry_get_staged_blob_id(
3403 &staged_blob_id, ie);
3406 return (*status_cb)(status_arg, status, staged_status,
3407 ie->path, blob_idp, staged_blob_idp, commit_idp, dirfd, de_name);
3410 static const struct got_error *
3411 status_old_new(void *arg, struct got_fileindex_entry *ie,
3412 struct dirent *de, const char *parent_path, int dirfd)
3414 const struct got_error *err = NULL;
3415 struct diff_dir_cb_arg *a = arg;
3416 char *abspath;
3418 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
3419 return got_error(GOT_ERR_CANCELLED);
3421 if (got_path_cmp(parent_path, a->status_path,
3422 strlen(parent_path), a->status_path_len) != 0 &&
3423 !got_path_is_child(parent_path, a->status_path, a->status_path_len))
3424 return NULL;
3426 if (parent_path[0]) {
3427 if (asprintf(&abspath, "%s/%s/%s", a->worktree->root_path,
3428 parent_path, de->d_name) == -1)
3429 return got_error_from_errno("asprintf");
3430 } else {
3431 if (asprintf(&abspath, "%s/%s", a->worktree->root_path,
3432 de->d_name) == -1)
3433 return got_error_from_errno("asprintf");
3436 err = report_file_status(ie, abspath, dirfd, de->d_name,
3437 a->status_cb, a->status_arg, a->repo, a->report_unchanged);
3438 free(abspath);
3439 return err;
3442 static const struct got_error *
3443 status_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path)
3445 struct diff_dir_cb_arg *a = arg;
3446 struct got_object_id blob_id, commit_id;
3447 unsigned char status;
3449 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
3450 return got_error(GOT_ERR_CANCELLED);
3452 if (!got_path_is_child(ie->path, a->status_path, a->status_path_len))
3453 return NULL;
3455 got_fileindex_entry_get_blob_id(&blob_id, ie);
3456 got_fileindex_entry_get_commit_id(&commit_id, ie);
3457 if (got_fileindex_entry_has_file_on_disk(ie))
3458 status = GOT_STATUS_MISSING;
3459 else
3460 status = GOT_STATUS_DELETE;
3461 return (*a->status_cb)(a->status_arg, status, get_staged_status(ie),
3462 ie->path, &blob_id, NULL, &commit_id, -1, NULL);
3465 static void
3466 free_ignores(struct got_pathlist_head *ignores)
3468 struct got_pathlist_entry *pe;
3470 TAILQ_FOREACH(pe, ignores, entry) {
3471 struct got_pathlist_head *ignorelist = pe->data;
3473 got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH);
3475 got_pathlist_free(ignores, GOT_PATHLIST_FREE_PATH);
3478 static const struct got_error *
3479 read_ignores(struct got_pathlist_head *ignores, const char *path, FILE *f)
3481 const struct got_error *err = NULL;
3482 struct got_pathlist_entry *pe = NULL;
3483 struct got_pathlist_head *ignorelist;
3484 char *line = NULL, *pattern, *dirpath = NULL;
3485 size_t linesize = 0;
3486 ssize_t linelen;
3488 ignorelist = calloc(1, sizeof(*ignorelist));
3489 if (ignorelist == NULL)
3490 return got_error_from_errno("calloc");
3491 TAILQ_INIT(ignorelist);
3493 while ((linelen = getline(&line, &linesize, f)) != -1) {
3494 if (linelen > 0 && line[linelen - 1] == '\n')
3495 line[linelen - 1] = '\0';
3497 /* Git's ignores may contain comments. */
3498 if (line[0] == '#')
3499 continue;
3501 /* Git's negated patterns are not (yet?) supported. */
3502 if (line[0] == '!')
3503 continue;
3505 if (asprintf(&pattern, "%s%s%s", path, path[0] ? "/" : "",
3506 line) == -1) {
3507 err = got_error_from_errno("asprintf");
3508 goto done;
3510 err = got_pathlist_insert(NULL, ignorelist, pattern, NULL);
3511 if (err)
3512 goto done;
3514 if (ferror(f)) {
3515 err = got_error_from_errno("getline");
3516 goto done;
3519 dirpath = strdup(path);
3520 if (dirpath == NULL) {
3521 err = got_error_from_errno("strdup");
3522 goto done;
3524 err = got_pathlist_insert(&pe, ignores, dirpath, ignorelist);
3525 done:
3526 free(line);
3527 if (err || pe == NULL) {
3528 free(dirpath);
3529 got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH);
3531 return err;
3534 static int
3535 match_ignores(struct got_pathlist_head *ignores, const char *path)
3537 struct got_pathlist_entry *pe;
3539 /* Handle patterns which match in all directories. */
3540 TAILQ_FOREACH(pe, ignores, entry) {
3541 struct got_pathlist_head *ignorelist = pe->data;
3542 struct got_pathlist_entry *pi;
3544 TAILQ_FOREACH(pi, ignorelist, entry) {
3545 const char *p, *pattern = pi->path;
3547 if (strncmp(pattern, "**/", 3) != 0)
3548 continue;
3549 pattern += 3;
3550 p = path;
3551 while (*p) {
3552 if (fnmatch(pattern, p,
3553 FNM_PATHNAME | FNM_LEADING_DIR)) {
3554 /* Retry in next directory. */
3555 while (*p && *p != '/')
3556 p++;
3557 while (*p == '/')
3558 p++;
3559 continue;
3561 return 1;
3567 * The ignores pathlist contains ignore lists from children before
3568 * parents, so we can find the most specific ignorelist by walking
3569 * ignores backwards.
3571 pe = TAILQ_LAST(ignores, got_pathlist_head);
3572 while (pe) {
3573 if (got_path_is_child(path, pe->path, pe->path_len)) {
3574 struct got_pathlist_head *ignorelist = pe->data;
3575 struct got_pathlist_entry *pi;
3576 TAILQ_FOREACH(pi, ignorelist, entry) {
3577 const char *pattern = pi->path;
3578 int flags = FNM_LEADING_DIR;
3579 if (strstr(pattern, "/**/") == NULL)
3580 flags |= FNM_PATHNAME;
3581 if (fnmatch(pattern, path, flags))
3582 continue;
3583 return 1;
3586 pe = TAILQ_PREV(pe, got_pathlist_head, entry);
3589 return 0;
3592 static const struct got_error *
3593 add_ignores(struct got_pathlist_head *ignores, const char *root_path,
3594 const char *path, int dirfd, const char *ignores_filename)
3596 const struct got_error *err = NULL;
3597 char *ignorespath;
3598 int fd = -1;
3599 FILE *ignoresfile = NULL;
3601 if (asprintf(&ignorespath, "%s/%s%s%s", root_path, path,
3602 path[0] ? "/" : "", ignores_filename) == -1)
3603 return got_error_from_errno("asprintf");
3605 if (dirfd != -1) {
3606 fd = openat(dirfd, ignores_filename,
3607 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
3608 if (fd == -1) {
3609 if (errno != ENOENT && errno != EACCES)
3610 err = got_error_from_errno2("openat",
3611 ignorespath);
3612 } else {
3613 ignoresfile = fdopen(fd, "r");
3614 if (ignoresfile == NULL)
3615 err = got_error_from_errno2("fdopen",
3616 ignorespath);
3617 else {
3618 fd = -1;
3619 err = read_ignores(ignores, path, ignoresfile);
3622 } else {
3623 ignoresfile = fopen(ignorespath, "re");
3624 if (ignoresfile == NULL) {
3625 if (errno != ENOENT && errno != EACCES)
3626 err = got_error_from_errno2("fopen",
3627 ignorespath);
3628 } else
3629 err = read_ignores(ignores, path, ignoresfile);
3632 if (ignoresfile && fclose(ignoresfile) == EOF && err == NULL)
3633 err = got_error_from_errno2("fclose", path);
3634 if (fd != -1 && close(fd) == -1 && err == NULL)
3635 err = got_error_from_errno2("close", path);
3636 free(ignorespath);
3637 return err;
3640 static const struct got_error *
3641 status_new(int *ignore, void *arg, struct dirent *de, const char *parent_path,
3642 int dirfd)
3644 const struct got_error *err = NULL;
3645 struct diff_dir_cb_arg *a = arg;
3646 char *path = NULL;
3648 if (ignore != NULL)
3649 *ignore = 0;
3651 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
3652 return got_error(GOT_ERR_CANCELLED);
3654 if (parent_path[0]) {
3655 if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1)
3656 return got_error_from_errno("asprintf");
3657 } else {
3658 path = de->d_name;
3661 if (de->d_type == DT_DIR) {
3662 if (!a->no_ignores && ignore != NULL &&
3663 match_ignores(a->ignores, path))
3664 *ignore = 1;
3665 } else if (!match_ignores(a->ignores, path) &&
3666 got_path_is_child(path, a->status_path, a->status_path_len))
3667 err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED,
3668 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3669 if (parent_path[0])
3670 free(path);
3671 return err;
3674 static const struct got_error *
3675 status_traverse(void *arg, const char *path, int dirfd)
3677 const struct got_error *err = NULL;
3678 struct diff_dir_cb_arg *a = arg;
3680 if (a->no_ignores)
3681 return NULL;
3683 err = add_ignores(a->ignores, a->worktree->root_path,
3684 path, dirfd, ".cvsignore");
3685 if (err)
3686 return err;
3688 err = add_ignores(a->ignores, a->worktree->root_path, path,
3689 dirfd, ".gitignore");
3691 return err;
3694 static const struct got_error *
3695 report_single_file_status(const char *path, const char *ondisk_path,
3696 struct got_fileindex *fileindex, got_worktree_status_cb status_cb,
3697 void *status_arg, struct got_repository *repo, int report_unchanged,
3698 struct got_pathlist_head *ignores, int no_ignores)
3700 struct got_fileindex_entry *ie;
3701 struct stat sb;
3703 ie = got_fileindex_entry_get(fileindex, path, strlen(path));
3704 if (ie)
3705 return report_file_status(ie, ondisk_path, -1, NULL,
3706 status_cb, status_arg, repo, report_unchanged);
3708 if (lstat(ondisk_path, &sb) == -1) {
3709 if (errno != ENOENT)
3710 return got_error_from_errno2("lstat", ondisk_path);
3711 return (*status_cb)(status_arg, GOT_STATUS_NONEXISTENT,
3712 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3715 if (!no_ignores && match_ignores(ignores, path))
3716 return NULL;
3718 if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode))
3719 return (*status_cb)(status_arg, GOT_STATUS_UNVERSIONED,
3720 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3722 return NULL;
3725 static const struct got_error *
3726 add_ignores_from_parent_paths(struct got_pathlist_head *ignores,
3727 const char *root_path, const char *path)
3729 const struct got_error *err;
3730 char *parent_path, *next_parent_path = NULL;
3732 err = add_ignores(ignores, root_path, "", -1,
3733 ".cvsignore");
3734 if (err)
3735 return err;
3737 err = add_ignores(ignores, root_path, "", -1,
3738 ".gitignore");
3739 if (err)
3740 return err;
3742 err = got_path_dirname(&parent_path, path);
3743 if (err) {
3744 if (err->code == GOT_ERR_BAD_PATH)
3745 return NULL; /* cannot traverse parent */
3746 return err;
3748 for (;;) {
3749 err = add_ignores(ignores, root_path, parent_path, -1,
3750 ".cvsignore");
3751 if (err)
3752 break;
3753 err = add_ignores(ignores, root_path, parent_path, -1,
3754 ".gitignore");
3755 if (err)
3756 break;
3757 err = got_path_dirname(&next_parent_path, parent_path);
3758 if (err) {
3759 if (err->code == GOT_ERR_BAD_PATH)
3760 err = NULL; /* traversed everything */
3761 break;
3763 if (got_path_is_root_dir(parent_path))
3764 break;
3765 free(parent_path);
3766 parent_path = next_parent_path;
3767 next_parent_path = NULL;
3770 free(parent_path);
3771 free(next_parent_path);
3772 return err;
3775 static const struct got_error *
3776 worktree_status(struct got_worktree *worktree, const char *path,
3777 struct got_fileindex *fileindex, struct got_repository *repo,
3778 got_worktree_status_cb status_cb, void *status_arg,
3779 got_cancel_cb cancel_cb, void *cancel_arg, int no_ignores,
3780 int report_unchanged)
3782 const struct got_error *err = NULL;
3783 int fd = -1;
3784 struct got_fileindex_diff_dir_cb fdiff_cb;
3785 struct diff_dir_cb_arg arg;
3786 char *ondisk_path = NULL;
3787 struct got_pathlist_head ignores;
3788 struct got_fileindex_entry *ie;
3790 TAILQ_INIT(&ignores);
3792 if (asprintf(&ondisk_path, "%s%s%s",
3793 worktree->root_path, path[0] ? "/" : "", path) == -1)
3794 return got_error_from_errno("asprintf");
3796 ie = got_fileindex_entry_get(fileindex, path, strlen(path));
3797 if (ie) {
3798 err = report_single_file_status(path, ondisk_path,
3799 fileindex, status_cb, status_arg, repo,
3800 report_unchanged, &ignores, no_ignores);
3801 goto done;
3804 fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
3805 if (fd == -1) {
3806 if (errno != ENOTDIR && errno != ENOENT && errno != EACCES &&
3807 !got_err_open_nofollow_on_symlink())
3808 err = got_error_from_errno2("open", ondisk_path);
3809 else {
3810 if (!no_ignores) {
3811 err = add_ignores_from_parent_paths(&ignores,
3812 worktree->root_path, ondisk_path);
3813 if (err)
3814 goto done;
3816 err = report_single_file_status(path, ondisk_path,
3817 fileindex, status_cb, status_arg, repo,
3818 report_unchanged, &ignores, no_ignores);
3820 } else {
3821 fdiff_cb.diff_old_new = status_old_new;
3822 fdiff_cb.diff_old = status_old;
3823 fdiff_cb.diff_new = status_new;
3824 fdiff_cb.diff_traverse = status_traverse;
3825 arg.fileindex = fileindex;
3826 arg.worktree = worktree;
3827 arg.status_path = path;
3828 arg.status_path_len = strlen(path);
3829 arg.repo = repo;
3830 arg.status_cb = status_cb;
3831 arg.status_arg = status_arg;
3832 arg.cancel_cb = cancel_cb;
3833 arg.cancel_arg = cancel_arg;
3834 arg.report_unchanged = report_unchanged;
3835 arg.no_ignores = no_ignores;
3836 if (!no_ignores) {
3837 err = add_ignores_from_parent_paths(&ignores,
3838 worktree->root_path, path);
3839 if (err)
3840 goto done;
3842 arg.ignores = &ignores;
3843 err = got_fileindex_diff_dir(fileindex, fd,
3844 worktree->root_path, path, repo, &fdiff_cb, &arg);
3846 done:
3847 free_ignores(&ignores);
3848 if (fd != -1 && close(fd) == -1 && err == NULL)
3849 err = got_error_from_errno("close");
3850 free(ondisk_path);
3851 return err;
3854 const struct got_error *
3855 got_worktree_status(struct got_worktree *worktree,
3856 struct got_pathlist_head *paths, struct got_repository *repo,
3857 int no_ignores, got_worktree_status_cb status_cb, void *status_arg,
3858 got_cancel_cb cancel_cb, void *cancel_arg)
3860 const struct got_error *err = NULL;
3861 char *fileindex_path = NULL;
3862 struct got_fileindex *fileindex = NULL;
3863 struct got_pathlist_entry *pe;
3865 err = open_fileindex(&fileindex, &fileindex_path, worktree);
3866 if (err)
3867 return err;
3869 TAILQ_FOREACH(pe, paths, entry) {
3870 err = worktree_status(worktree, pe->path, fileindex, repo,
3871 status_cb, status_arg, cancel_cb, cancel_arg,
3872 no_ignores, 0);
3873 if (err)
3874 break;
3876 free(fileindex_path);
3877 got_fileindex_free(fileindex);
3878 return err;
3881 const struct got_error *
3882 got_worktree_resolve_path(char **wt_path, struct got_worktree *worktree,
3883 const char *arg)
3885 const struct got_error *err = NULL;
3886 char *resolved = NULL, *cwd = NULL, *path = NULL;
3887 size_t len;
3888 struct stat sb;
3889 char *abspath = NULL;
3890 char canonpath[PATH_MAX];
3892 *wt_path = NULL;
3894 cwd = getcwd(NULL, 0);
3895 if (cwd == NULL)
3896 return got_error_from_errno("getcwd");
3898 if (lstat(arg, &sb) == -1) {
3899 if (errno != ENOENT) {
3900 err = got_error_from_errno2("lstat", arg);
3901 goto done;
3903 sb.st_mode = 0;
3905 if (S_ISLNK(sb.st_mode)) {
3907 * We cannot use realpath(3) with symlinks since we want to
3908 * operate on the symlink itself.
3909 * But we can make the path absolute, assuming it is relative
3910 * to the current working directory, and then canonicalize it.
3912 if (!got_path_is_absolute(arg)) {
3913 if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) {
3914 err = got_error_from_errno("asprintf");
3915 goto done;
3919 err = got_canonpath(abspath ? abspath : arg, canonpath,
3920 sizeof(canonpath));
3921 if (err)
3922 goto done;
3923 resolved = strdup(canonpath);
3924 if (resolved == NULL) {
3925 err = got_error_from_errno("strdup");
3926 goto done;
3928 } else {
3929 resolved = realpath(arg, NULL);
3930 if (resolved == NULL) {
3931 if (errno != ENOENT) {
3932 err = got_error_from_errno2("realpath", arg);
3933 goto done;
3935 if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) {
3936 err = got_error_from_errno("asprintf");
3937 goto done;
3939 err = got_canonpath(abspath, canonpath,
3940 sizeof(canonpath));
3941 if (err)
3942 goto done;
3943 resolved = strdup(canonpath);
3944 if (resolved == NULL) {
3945 err = got_error_from_errno("strdup");
3946 goto done;
3951 if (strncmp(got_worktree_get_root_path(worktree), resolved,
3952 strlen(got_worktree_get_root_path(worktree)))) {
3953 err = got_error_path(resolved, GOT_ERR_BAD_PATH);
3954 goto done;
3957 if (strlen(resolved) > strlen(got_worktree_get_root_path(worktree))) {
3958 err = got_path_skip_common_ancestor(&path,
3959 got_worktree_get_root_path(worktree), resolved);
3960 if (err)
3961 goto done;
3962 } else {
3963 path = strdup("");
3964 if (path == NULL) {
3965 err = got_error_from_errno("strdup");
3966 goto done;
3970 /* XXX status walk can't deal with trailing slash! */
3971 len = strlen(path);
3972 while (len > 0 && path[len - 1] == '/') {
3973 path[len - 1] = '\0';
3974 len--;
3976 done:
3977 free(abspath);
3978 free(resolved);
3979 free(cwd);
3980 if (err == NULL)
3981 *wt_path = path;
3982 else
3983 free(path);
3984 return err;
3987 struct schedule_addition_args {
3988 struct got_worktree *worktree;
3989 struct got_fileindex *fileindex;
3990 got_worktree_checkout_cb progress_cb;
3991 void *progress_arg;
3992 struct got_repository *repo;
3995 static const struct got_error *
3996 schedule_addition(void *arg, unsigned char status, unsigned char staged_status,
3997 const char *relpath, struct got_object_id *blob_id,
3998 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
3999 int dirfd, const char *de_name)
4001 struct schedule_addition_args *a = arg;
4002 const struct got_error *err = NULL;
4003 struct got_fileindex_entry *ie;
4004 struct stat sb;
4005 char *ondisk_path;
4007 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
4008 relpath) == -1)
4009 return got_error_from_errno("asprintf");
4011 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
4012 if (ie) {
4013 err = get_file_status(&status, &sb, ie, ondisk_path, dirfd,
4014 de_name, a->repo);
4015 if (err)
4016 goto done;
4017 /* Re-adding an existing entry is a no-op. */
4018 if (status == GOT_STATUS_ADD)
4019 goto done;
4020 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
4021 if (err)
4022 goto done;
4025 if (status != GOT_STATUS_UNVERSIONED) {
4026 if (status == GOT_STATUS_NONEXISTENT)
4027 err = got_error_set_errno(ENOENT, ondisk_path);
4028 else
4029 err = got_error_path(ondisk_path, GOT_ERR_FILE_STATUS);
4030 goto done;
4033 err = got_fileindex_entry_alloc(&ie, relpath);
4034 if (err)
4035 goto done;
4036 err = got_fileindex_entry_update(ie, a->worktree->root_fd,
4037 relpath, NULL, NULL, 1);
4038 if (err) {
4039 got_fileindex_entry_free(ie);
4040 goto done;
4042 err = got_fileindex_entry_add(a->fileindex, ie);
4043 if (err) {
4044 got_fileindex_entry_free(ie);
4045 goto done;
4047 done:
4048 free(ondisk_path);
4049 if (err)
4050 return err;
4051 if (status == GOT_STATUS_ADD)
4052 return NULL;
4053 return (*a->progress_cb)(a->progress_arg, GOT_STATUS_ADD, relpath);
4056 const struct got_error *
4057 got_worktree_schedule_add(struct got_worktree *worktree,
4058 struct got_pathlist_head *paths,
4059 got_worktree_checkout_cb progress_cb, void *progress_arg,
4060 struct got_repository *repo, int no_ignores)
4062 struct got_fileindex *fileindex = NULL;
4063 char *fileindex_path = NULL;
4064 const struct got_error *err = NULL, *sync_err, *unlockerr;
4065 struct got_pathlist_entry *pe;
4066 struct schedule_addition_args saa;
4068 err = lock_worktree(worktree, LOCK_EX);
4069 if (err)
4070 return err;
4072 err = open_fileindex(&fileindex, &fileindex_path, worktree);
4073 if (err)
4074 goto done;
4076 saa.worktree = worktree;
4077 saa.fileindex = fileindex;
4078 saa.progress_cb = progress_cb;
4079 saa.progress_arg = progress_arg;
4080 saa.repo = repo;
4082 TAILQ_FOREACH(pe, paths, entry) {
4083 err = worktree_status(worktree, pe->path, fileindex, repo,
4084 schedule_addition, &saa, NULL, NULL, no_ignores, 0);
4085 if (err)
4086 break;
4088 sync_err = sync_fileindex(fileindex, fileindex_path);
4089 if (sync_err && err == NULL)
4090 err = sync_err;
4091 done:
4092 free(fileindex_path);
4093 if (fileindex)
4094 got_fileindex_free(fileindex);
4095 unlockerr = lock_worktree(worktree, LOCK_SH);
4096 if (unlockerr && err == NULL)
4097 err = unlockerr;
4098 return err;
4101 struct schedule_deletion_args {
4102 struct got_worktree *worktree;
4103 struct got_fileindex *fileindex;
4104 got_worktree_delete_cb progress_cb;
4105 void *progress_arg;
4106 struct got_repository *repo;
4107 int delete_local_mods;
4108 int keep_on_disk;
4109 int ignore_missing_paths;
4110 const char *status_codes;
4113 static const struct got_error *
4114 schedule_for_deletion(void *arg, unsigned char status,
4115 unsigned char staged_status, const char *relpath,
4116 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
4117 struct got_object_id *commit_id, int dirfd, const char *de_name)
4119 struct schedule_deletion_args *a = arg;
4120 const struct got_error *err = NULL;
4121 struct got_fileindex_entry *ie = NULL;
4122 struct stat sb;
4123 char *ondisk_path;
4125 if (status == GOT_STATUS_NONEXISTENT) {
4126 if (a->ignore_missing_paths)
4127 return NULL;
4128 return got_error_set_errno(ENOENT, relpath);
4131 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
4132 if (ie == NULL)
4133 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
4135 staged_status = get_staged_status(ie);
4136 if (staged_status != GOT_STATUS_NO_CHANGE) {
4137 if (staged_status == GOT_STATUS_DELETE)
4138 return NULL;
4139 return got_error_path(relpath, GOT_ERR_FILE_STAGED);
4142 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
4143 relpath) == -1)
4144 return got_error_from_errno("asprintf");
4146 err = get_file_status(&status, &sb, ie, ondisk_path, dirfd, de_name,
4147 a->repo);
4148 if (err)
4149 goto done;
4151 if (a->status_codes) {
4152 size_t ncodes = strlen(a->status_codes);
4153 int i;
4154 for (i = 0; i < ncodes ; i++) {
4155 if (status == a->status_codes[i])
4156 break;
4158 if (i == ncodes) {
4159 /* Do not delete files in non-matching status. */
4160 free(ondisk_path);
4161 return NULL;
4163 if (a->status_codes[i] != GOT_STATUS_MODIFY &&
4164 a->status_codes[i] != GOT_STATUS_MISSING) {
4165 static char msg[64];
4166 snprintf(msg, sizeof(msg),
4167 "invalid status code '%c'", a->status_codes[i]);
4168 err = got_error_msg(GOT_ERR_FILE_STATUS, msg);
4169 goto done;
4173 if (status != GOT_STATUS_NO_CHANGE) {
4174 if (status == GOT_STATUS_DELETE)
4175 goto done;
4176 if (status == GOT_STATUS_MODIFY && !a->delete_local_mods) {
4177 err = got_error_path(relpath, GOT_ERR_FILE_MODIFIED);
4178 goto done;
4180 if (status == GOT_STATUS_MISSING && !a->ignore_missing_paths) {
4181 err = got_error_set_errno(ENOENT, relpath);
4182 goto done;
4184 if (status != GOT_STATUS_MODIFY &&
4185 status != GOT_STATUS_MISSING) {
4186 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
4187 goto done;
4191 if (!a->keep_on_disk && status != GOT_STATUS_MISSING) {
4192 size_t root_len;
4194 if (dirfd != -1) {
4195 if (unlinkat(dirfd, de_name, 0) == -1) {
4196 err = got_error_from_errno2("unlinkat",
4197 ondisk_path);
4198 goto done;
4200 } else if (unlink(ondisk_path) == -1) {
4201 err = got_error_from_errno2("unlink", ondisk_path);
4202 goto done;
4205 root_len = strlen(a->worktree->root_path);
4206 do {
4207 char *parent;
4208 err = got_path_dirname(&parent, ondisk_path);
4209 if (err)
4210 goto done;
4211 free(ondisk_path);
4212 ondisk_path = parent;
4213 if (rmdir(ondisk_path) == -1) {
4214 if (errno != ENOTEMPTY)
4215 err = got_error_from_errno2("rmdir",
4216 ondisk_path);
4217 break;
4219 } while (got_path_cmp(ondisk_path, a->worktree->root_path,
4220 strlen(ondisk_path), root_len) != 0);
4223 got_fileindex_entry_mark_deleted_from_disk(ie);
4224 done:
4225 free(ondisk_path);
4226 if (err)
4227 return err;
4228 if (status == GOT_STATUS_DELETE)
4229 return NULL;
4230 return (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE,
4231 staged_status, relpath);
4234 const struct got_error *
4235 got_worktree_schedule_delete(struct got_worktree *worktree,
4236 struct got_pathlist_head *paths, int delete_local_mods,
4237 const char *status_codes,
4238 got_worktree_delete_cb progress_cb, void *progress_arg,
4239 struct got_repository *repo, int keep_on_disk, int ignore_missing_paths)
4241 struct got_fileindex *fileindex = NULL;
4242 char *fileindex_path = NULL;
4243 const struct got_error *err = NULL, *sync_err, *unlockerr;
4244 struct got_pathlist_entry *pe;
4245 struct schedule_deletion_args sda;
4247 err = lock_worktree(worktree, LOCK_EX);
4248 if (err)
4249 return err;
4251 err = open_fileindex(&fileindex, &fileindex_path, worktree);
4252 if (err)
4253 goto done;
4255 sda.worktree = worktree;
4256 sda.fileindex = fileindex;
4257 sda.progress_cb = progress_cb;
4258 sda.progress_arg = progress_arg;
4259 sda.repo = repo;
4260 sda.delete_local_mods = delete_local_mods;
4261 sda.keep_on_disk = keep_on_disk;
4262 sda.ignore_missing_paths = ignore_missing_paths;
4263 sda.status_codes = status_codes;
4265 TAILQ_FOREACH(pe, paths, entry) {
4266 err = worktree_status(worktree, pe->path, fileindex, repo,
4267 schedule_for_deletion, &sda, NULL, NULL, 1, 1);
4268 if (err)
4269 break;
4271 sync_err = sync_fileindex(fileindex, fileindex_path);
4272 if (sync_err && err == NULL)
4273 err = sync_err;
4274 done:
4275 free(fileindex_path);
4276 if (fileindex)
4277 got_fileindex_free(fileindex);
4278 unlockerr = lock_worktree(worktree, LOCK_SH);
4279 if (unlockerr && err == NULL)
4280 err = unlockerr;
4281 return err;
4284 static const struct got_error *
4285 copy_one_line(FILE *infile, FILE *outfile, FILE *rejectfile)
4287 const struct got_error *err = NULL;
4288 char *line = NULL;
4289 size_t linesize = 0, n;
4290 ssize_t linelen;
4292 linelen = getline(&line, &linesize, infile);
4293 if (linelen == -1) {
4294 if (ferror(infile)) {
4295 err = got_error_from_errno("getline");
4296 goto done;
4298 return NULL;
4300 if (outfile) {
4301 n = fwrite(line, 1, linelen, outfile);
4302 if (n != linelen) {
4303 err = got_ferror(outfile, GOT_ERR_IO);
4304 goto done;
4307 if (rejectfile) {
4308 n = fwrite(line, 1, linelen, rejectfile);
4309 if (n != linelen)
4310 err = got_ferror(rejectfile, GOT_ERR_IO);
4312 done:
4313 free(line);
4314 return err;
4317 static const struct got_error *
4318 skip_one_line(FILE *f)
4320 char *line = NULL;
4321 size_t linesize = 0;
4322 ssize_t linelen;
4324 linelen = getline(&line, &linesize, f);
4325 if (linelen == -1) {
4326 if (ferror(f))
4327 return got_error_from_errno("getline");
4328 return NULL;
4330 free(line);
4331 return NULL;
4334 static const struct got_error *
4335 copy_change(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4336 int start_old, int end_old, int start_new, int end_new,
4337 FILE *outfile, FILE *rejectfile)
4339 const struct got_error *err;
4341 /* Copy old file's lines leading up to patch. */
4342 while (!feof(f1) && *line_cur1 < start_old) {
4343 err = copy_one_line(f1, outfile, NULL);
4344 if (err)
4345 return err;
4346 (*line_cur1)++;
4348 /* Skip new file's lines leading up to patch. */
4349 while (!feof(f2) && *line_cur2 < start_new) {
4350 if (rejectfile)
4351 err = copy_one_line(f2, NULL, rejectfile);
4352 else
4353 err = skip_one_line(f2);
4354 if (err)
4355 return err;
4356 (*line_cur2)++;
4358 /* Copy patched lines. */
4359 while (!feof(f2) && *line_cur2 <= end_new) {
4360 err = copy_one_line(f2, outfile, NULL);
4361 if (err)
4362 return err;
4363 (*line_cur2)++;
4365 /* Skip over old file's replaced lines. */
4366 while (!feof(f1) && *line_cur1 <= end_old) {
4367 if (rejectfile)
4368 err = copy_one_line(f1, NULL, rejectfile);
4369 else
4370 err = skip_one_line(f1);
4371 if (err)
4372 return err;
4373 (*line_cur1)++;
4376 return NULL;
4379 static const struct got_error *
4380 copy_remaining_content(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4381 FILE *outfile, FILE *rejectfile)
4383 const struct got_error *err;
4385 if (outfile) {
4386 /* Copy old file's lines until EOF. */
4387 while (!feof(f1)) {
4388 err = copy_one_line(f1, outfile, NULL);
4389 if (err)
4390 return err;
4391 (*line_cur1)++;
4394 if (rejectfile) {
4395 /* Copy new file's lines until EOF. */
4396 while (!feof(f2)) {
4397 err = copy_one_line(f2, NULL, rejectfile);
4398 if (err)
4399 return err;
4400 (*line_cur2)++;
4404 return NULL;
4407 static const struct got_error *
4408 apply_or_reject_change(int *choice, int *nchunks_used,
4409 struct diff_result *diff_result, int n,
4410 const char *relpath, FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4411 FILE *outfile, FILE *rejectfile, int changeno, int nchanges,
4412 got_worktree_patch_cb patch_cb, void *patch_arg)
4414 const struct got_error *err = NULL;
4415 struct diff_chunk_context cc = {};
4416 int start_old, end_old, start_new, end_new;
4417 FILE *hunkfile;
4418 struct diff_output_unidiff_state *diff_state;
4419 struct diff_input_info diff_info;
4420 int rc;
4422 *choice = GOT_PATCH_CHOICE_NONE;
4424 /* Get changed line numbers without context lines for copy_change(). */
4425 diff_chunk_context_load_change(&cc, NULL, diff_result, n, 0);
4426 start_old = cc.left.start;
4427 end_old = cc.left.end;
4428 start_new = cc.right.start;
4429 end_new = cc.right.end;
4431 /* Get the same change with context lines for display. */
4432 memset(&cc, 0, sizeof(cc));
4433 diff_chunk_context_load_change(&cc, nchunks_used, diff_result, n, 3);
4435 memset(&diff_info, 0, sizeof(diff_info));
4436 diff_info.left_path = relpath;
4437 diff_info.right_path = relpath;
4439 diff_state = diff_output_unidiff_state_alloc();
4440 if (diff_state == NULL)
4441 return got_error_set_errno(ENOMEM,
4442 "diff_output_unidiff_state_alloc");
4444 hunkfile = got_opentemp();
4445 if (hunkfile == NULL) {
4446 err = got_error_from_errno("got_opentemp");
4447 goto done;
4450 rc = diff_output_unidiff_chunk(NULL, hunkfile, diff_state, &diff_info,
4451 diff_result, &cc);
4452 if (rc != DIFF_RC_OK) {
4453 err = got_error_set_errno(rc, "diff_output_unidiff_chunk");
4454 goto done;
4457 if (fseek(hunkfile, 0L, SEEK_SET) == -1) {
4458 err = got_ferror(hunkfile, GOT_ERR_IO);
4459 goto done;
4462 err = (*patch_cb)(choice, patch_arg, GOT_STATUS_MODIFY, relpath,
4463 hunkfile, changeno, nchanges);
4464 if (err)
4465 goto done;
4467 switch (*choice) {
4468 case GOT_PATCH_CHOICE_YES:
4469 err = copy_change(f1, f2, line_cur1, line_cur2, start_old,
4470 end_old, start_new, end_new, outfile, rejectfile);
4471 break;
4472 case GOT_PATCH_CHOICE_NO:
4473 err = copy_change(f1, f2, line_cur1, line_cur2, start_old,
4474 end_old, start_new, end_new, rejectfile, outfile);
4475 break;
4476 case GOT_PATCH_CHOICE_QUIT:
4477 break;
4478 default:
4479 err = got_error(GOT_ERR_PATCH_CHOICE);
4480 break;
4482 done:
4483 diff_output_unidiff_state_free(diff_state);
4484 if (hunkfile && fclose(hunkfile) == EOF && err == NULL)
4485 err = got_error_from_errno("fclose");
4486 return err;
4489 struct revert_file_args {
4490 struct got_worktree *worktree;
4491 struct got_fileindex *fileindex;
4492 got_worktree_checkout_cb progress_cb;
4493 void *progress_arg;
4494 got_worktree_patch_cb patch_cb;
4495 void *patch_arg;
4496 struct got_repository *repo;
4497 int unlink_added_files;
4500 static const struct got_error *
4501 create_patched_content(char **path_outfile, int reverse_patch,
4502 struct got_object_id *blob_id, const char *path2,
4503 int dirfd2, const char *de_name2,
4504 const char *relpath, struct got_repository *repo,
4505 got_worktree_patch_cb patch_cb, void *patch_arg)
4507 const struct got_error *err, *free_err;
4508 struct got_blob_object *blob = NULL;
4509 FILE *f1 = NULL, *f2 = NULL, *outfile = NULL;
4510 int fd = -1, fd2 = -1;
4511 char link_target[PATH_MAX];
4512 ssize_t link_len = 0;
4513 char *path1 = NULL, *id_str = NULL;
4514 struct stat sb2;
4515 struct got_diffreg_result *diffreg_result = NULL;
4516 int line_cur1 = 1, line_cur2 = 1, have_content = 0;
4517 int i = 0, n = 0, nchunks_used = 0, nchanges = 0;
4519 *path_outfile = NULL;
4521 err = got_object_id_str(&id_str, blob_id);
4522 if (err)
4523 return err;
4525 if (dirfd2 != -1) {
4526 fd2 = openat(dirfd2, de_name2,
4527 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4528 if (fd2 == -1) {
4529 if (!got_err_open_nofollow_on_symlink()) {
4530 err = got_error_from_errno2("openat", path2);
4531 goto done;
4533 link_len = readlinkat(dirfd2, de_name2,
4534 link_target, sizeof(link_target));
4535 if (link_len == -1) {
4536 return got_error_from_errno2("readlinkat",
4537 path2);
4539 sb2.st_mode = S_IFLNK;
4540 sb2.st_size = link_len;
4542 } else {
4543 fd2 = open(path2, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4544 if (fd2 == -1) {
4545 if (!got_err_open_nofollow_on_symlink()) {
4546 err = got_error_from_errno2("open", path2);
4547 goto done;
4549 link_len = readlink(path2, link_target,
4550 sizeof(link_target));
4551 if (link_len == -1)
4552 return got_error_from_errno2("readlink", path2);
4553 sb2.st_mode = S_IFLNK;
4554 sb2.st_size = link_len;
4557 if (fd2 != -1) {
4558 if (fstat(fd2, &sb2) == -1) {
4559 err = got_error_from_errno2("fstat", path2);
4560 goto done;
4563 f2 = fdopen(fd2, "r");
4564 if (f2 == NULL) {
4565 err = got_error_from_errno2("fdopen", path2);
4566 goto done;
4568 fd2 = -1;
4569 } else {
4570 size_t n;
4571 f2 = got_opentemp();
4572 if (f2 == NULL) {
4573 err = got_error_from_errno2("got_opentemp", path2);
4574 goto done;
4576 n = fwrite(link_target, 1, link_len, f2);
4577 if (n != link_len) {
4578 err = got_ferror(f2, GOT_ERR_IO);
4579 goto done;
4581 if (fflush(f2) == EOF) {
4582 err = got_error_from_errno("fflush");
4583 goto done;
4585 rewind(f2);
4588 fd = got_opentempfd();
4589 if (fd == -1) {
4590 err = got_error_from_errno("got_opentempfd");
4591 goto done;
4594 err = got_object_open_as_blob(&blob, repo, blob_id, 8192, fd);
4595 if (err)
4596 goto done;
4598 err = got_opentemp_named(&path1, &f1, "got-patched-blob", "");
4599 if (err)
4600 goto done;
4602 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob);
4603 if (err)
4604 goto done;
4606 err = got_diff_files(&diffreg_result, f1, 1, id_str, f2, 1, path2,
4607 3, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS);
4608 if (err)
4609 goto done;
4611 err = got_opentemp_named(path_outfile, &outfile, "got-patched-content",
4612 "");
4613 if (err)
4614 goto done;
4616 if (fseek(f1, 0L, SEEK_SET) == -1)
4617 return got_ferror(f1, GOT_ERR_IO);
4618 if (fseek(f2, 0L, SEEK_SET) == -1)
4619 return got_ferror(f2, GOT_ERR_IO);
4621 /* Count the number of actual changes in the diff result. */
4622 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
4623 struct diff_chunk_context cc = {};
4624 diff_chunk_context_load_change(&cc, &nchunks_used,
4625 diffreg_result->result, n, 0);
4626 nchanges++;
4628 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
4629 int choice;
4630 err = apply_or_reject_change(&choice, &nchunks_used,
4631 diffreg_result->result, n, relpath, f1, f2,
4632 &line_cur1, &line_cur2,
4633 reverse_patch ? NULL : outfile,
4634 reverse_patch ? outfile : NULL,
4635 ++i, nchanges, patch_cb, patch_arg);
4636 if (err)
4637 goto done;
4638 if (choice == GOT_PATCH_CHOICE_YES)
4639 have_content = 1;
4640 else if (choice == GOT_PATCH_CHOICE_QUIT)
4641 break;
4643 if (have_content) {
4644 err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2,
4645 reverse_patch ? NULL : outfile,
4646 reverse_patch ? outfile : NULL);
4647 if (err)
4648 goto done;
4650 if (!S_ISLNK(sb2.st_mode)) {
4651 mode_t mode;
4653 mode = apply_umask(sb2.st_mode);
4654 if (fchmod(fileno(outfile), mode) == -1) {
4655 err = got_error_from_errno2("fchmod", path2);
4656 goto done;
4660 done:
4661 free(id_str);
4662 if (fd != -1 && close(fd) == -1 && err == NULL)
4663 err = got_error_from_errno("close");
4664 if (blob)
4665 got_object_blob_close(blob);
4666 free_err = got_diffreg_result_free(diffreg_result);
4667 if (err == NULL)
4668 err = free_err;
4669 if (f1 && fclose(f1) == EOF && err == NULL)
4670 err = got_error_from_errno2("fclose", path1);
4671 if (f2 && fclose(f2) == EOF && err == NULL)
4672 err = got_error_from_errno2("fclose", path2);
4673 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
4674 err = got_error_from_errno2("close", path2);
4675 if (outfile && fclose(outfile) == EOF && err == NULL)
4676 err = got_error_from_errno2("fclose", *path_outfile);
4677 if (path1 && unlink(path1) == -1 && err == NULL)
4678 err = got_error_from_errno2("unlink", path1);
4679 if (err || !have_content) {
4680 if (*path_outfile && unlink(*path_outfile) == -1 && err == NULL)
4681 err = got_error_from_errno2("unlink", *path_outfile);
4682 free(*path_outfile);
4683 *path_outfile = NULL;
4685 free(path1);
4686 return err;
4689 static const struct got_error *
4690 revert_file(void *arg, unsigned char status, unsigned char staged_status,
4691 const char *relpath, struct got_object_id *blob_id,
4692 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4693 int dirfd, const char *de_name)
4695 struct revert_file_args *a = arg;
4696 const struct got_error *err = NULL;
4697 char *parent_path = NULL;
4698 struct got_fileindex_entry *ie;
4699 struct got_commit_object *base_commit = NULL;
4700 struct got_tree_object *tree = NULL;
4701 struct got_object_id *tree_id = NULL;
4702 const struct got_tree_entry *te = NULL;
4703 char *tree_path = NULL, *te_name;
4704 char *ondisk_path = NULL, *path_content = NULL;
4705 struct got_blob_object *blob = NULL;
4706 int fd = -1;
4708 /* Reverting a staged deletion is a no-op. */
4709 if (status == GOT_STATUS_DELETE &&
4710 staged_status != GOT_STATUS_NO_CHANGE)
4711 return NULL;
4713 if (status == GOT_STATUS_UNVERSIONED)
4714 return (*a->progress_cb)(a->progress_arg,
4715 GOT_STATUS_UNVERSIONED, relpath);
4717 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
4718 if (ie == NULL)
4719 return got_error_path(relpath, GOT_ERR_BAD_PATH);
4721 /* Construct in-repository path of tree which contains this blob. */
4722 err = got_path_dirname(&parent_path, ie->path);
4723 if (err) {
4724 if (err->code != GOT_ERR_BAD_PATH)
4725 goto done;
4726 parent_path = strdup("/");
4727 if (parent_path == NULL) {
4728 err = got_error_from_errno("strdup");
4729 goto done;
4732 if (got_path_is_root_dir(a->worktree->path_prefix)) {
4733 tree_path = strdup(parent_path);
4734 if (tree_path == NULL) {
4735 err = got_error_from_errno("strdup");
4736 goto done;
4738 } else {
4739 if (got_path_is_root_dir(parent_path)) {
4740 tree_path = strdup(a->worktree->path_prefix);
4741 if (tree_path == NULL) {
4742 err = got_error_from_errno("strdup");
4743 goto done;
4745 } else {
4746 if (asprintf(&tree_path, "%s/%s",
4747 a->worktree->path_prefix, parent_path) == -1) {
4748 err = got_error_from_errno("asprintf");
4749 goto done;
4754 err = got_object_open_as_commit(&base_commit, a->repo,
4755 a->worktree->base_commit_id);
4756 if (err)
4757 goto done;
4759 err = got_object_id_by_path(&tree_id, a->repo, base_commit, tree_path);
4760 if (err) {
4761 if (!(err->code == GOT_ERR_NO_TREE_ENTRY &&
4762 (status == GOT_STATUS_ADD ||
4763 staged_status == GOT_STATUS_ADD)))
4764 goto done;
4765 } else {
4766 err = got_object_open_as_tree(&tree, a->repo, tree_id);
4767 if (err)
4768 goto done;
4770 err = got_path_basename(&te_name, ie->path);
4771 if (err)
4772 goto done;
4774 te = got_object_tree_find_entry(tree, te_name);
4775 free(te_name);
4776 if (te == NULL && status != GOT_STATUS_ADD &&
4777 staged_status != GOT_STATUS_ADD) {
4778 err = got_error_path(ie->path, GOT_ERR_NO_TREE_ENTRY);
4779 goto done;
4783 switch (status) {
4784 case GOT_STATUS_ADD:
4785 if (a->patch_cb) {
4786 int choice = GOT_PATCH_CHOICE_NONE;
4787 err = (*a->patch_cb)(&choice, a->patch_arg,
4788 status, ie->path, NULL, 1, 1);
4789 if (err)
4790 goto done;
4791 if (choice != GOT_PATCH_CHOICE_YES)
4792 break;
4794 err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_REVERT,
4795 ie->path);
4796 if (err)
4797 goto done;
4798 got_fileindex_entry_remove(a->fileindex, ie);
4799 if (a->unlink_added_files) {
4800 if (asprintf(&ondisk_path, "%s/%s",
4801 got_worktree_get_root_path(a->worktree),
4802 relpath) == -1) {
4803 err = got_error_from_errno("asprintf");
4804 goto done;
4806 if (unlink(ondisk_path) == -1) {
4807 err = got_error_from_errno2("unlink",
4808 ondisk_path);
4809 break;
4812 break;
4813 case GOT_STATUS_DELETE:
4814 if (a->patch_cb) {
4815 int choice = GOT_PATCH_CHOICE_NONE;
4816 err = (*a->patch_cb)(&choice, a->patch_arg,
4817 status, ie->path, NULL, 1, 1);
4818 if (err)
4819 goto done;
4820 if (choice != GOT_PATCH_CHOICE_YES)
4821 break;
4823 /* fall through */
4824 case GOT_STATUS_MODIFY:
4825 case GOT_STATUS_MODE_CHANGE:
4826 case GOT_STATUS_CONFLICT:
4827 case GOT_STATUS_MISSING: {
4828 struct got_object_id id;
4829 if (staged_status == GOT_STATUS_ADD ||
4830 staged_status == GOT_STATUS_MODIFY)
4831 got_fileindex_entry_get_staged_blob_id(&id, ie);
4832 else
4833 got_fileindex_entry_get_blob_id(&id, ie);
4834 fd = got_opentempfd();
4835 if (fd == -1) {
4836 err = got_error_from_errno("got_opentempfd");
4837 goto done;
4840 err = got_object_open_as_blob(&blob, a->repo, &id, 8192, fd);
4841 if (err)
4842 goto done;
4844 if (asprintf(&ondisk_path, "%s/%s",
4845 got_worktree_get_root_path(a->worktree), relpath) == -1) {
4846 err = got_error_from_errno("asprintf");
4847 goto done;
4850 if (a->patch_cb && (status == GOT_STATUS_MODIFY ||
4851 status == GOT_STATUS_CONFLICT)) {
4852 int is_bad_symlink = 0;
4853 err = create_patched_content(&path_content, 1, &id,
4854 ondisk_path, dirfd, de_name, ie->path, a->repo,
4855 a->patch_cb, a->patch_arg);
4856 if (err || path_content == NULL)
4857 break;
4858 if (te && S_ISLNK(te->mode)) {
4859 if (unlink(path_content) == -1) {
4860 err = got_error_from_errno2("unlink",
4861 path_content);
4862 break;
4864 err = install_symlink(&is_bad_symlink,
4865 a->worktree, ondisk_path, ie->path,
4866 blob, 0, 1, 0, 0, a->repo,
4867 a->progress_cb, a->progress_arg);
4868 } else {
4869 if (rename(path_content, ondisk_path) == -1) {
4870 err = got_error_from_errno3("rename",
4871 path_content, ondisk_path);
4872 goto done;
4875 } else {
4876 int is_bad_symlink = 0;
4877 if (te && S_ISLNK(te->mode)) {
4878 err = install_symlink(&is_bad_symlink,
4879 a->worktree, ondisk_path, ie->path,
4880 blob, 0, 1, 0, 0, a->repo,
4881 a->progress_cb, a->progress_arg);
4882 } else {
4883 err = install_blob(a->worktree, ondisk_path,
4884 ie->path,
4885 te ? te->mode : GOT_DEFAULT_FILE_MODE,
4886 got_fileindex_perms_to_st(ie), blob,
4887 0, 1, 0, 0, a->repo,
4888 a->progress_cb, a->progress_arg);
4890 if (err)
4891 goto done;
4892 if (status == GOT_STATUS_DELETE ||
4893 status == GOT_STATUS_MODE_CHANGE) {
4894 err = got_fileindex_entry_update(ie,
4895 a->worktree->root_fd, relpath,
4896 blob->id.sha1,
4897 a->worktree->base_commit_id->sha1, 1);
4898 if (err)
4899 goto done;
4901 if (is_bad_symlink) {
4902 got_fileindex_entry_filetype_set(ie,
4903 GOT_FILEIDX_MODE_BAD_SYMLINK);
4906 break;
4908 default:
4909 break;
4911 done:
4912 free(ondisk_path);
4913 free(path_content);
4914 free(parent_path);
4915 free(tree_path);
4916 if (fd != -1 && close(fd) == -1 && err == NULL)
4917 err = got_error_from_errno("close");
4918 if (blob)
4919 got_object_blob_close(blob);
4920 if (tree)
4921 got_object_tree_close(tree);
4922 free(tree_id);
4923 if (base_commit)
4924 got_object_commit_close(base_commit);
4925 return err;
4928 const struct got_error *
4929 got_worktree_revert(struct got_worktree *worktree,
4930 struct got_pathlist_head *paths,
4931 got_worktree_checkout_cb progress_cb, void *progress_arg,
4932 got_worktree_patch_cb patch_cb, void *patch_arg,
4933 struct got_repository *repo)
4935 struct got_fileindex *fileindex = NULL;
4936 char *fileindex_path = NULL;
4937 const struct got_error *err = NULL, *unlockerr = NULL;
4938 const struct got_error *sync_err = NULL;
4939 struct got_pathlist_entry *pe;
4940 struct revert_file_args rfa;
4942 err = lock_worktree(worktree, LOCK_EX);
4943 if (err)
4944 return err;
4946 err = open_fileindex(&fileindex, &fileindex_path, worktree);
4947 if (err)
4948 goto done;
4950 rfa.worktree = worktree;
4951 rfa.fileindex = fileindex;
4952 rfa.progress_cb = progress_cb;
4953 rfa.progress_arg = progress_arg;
4954 rfa.patch_cb = patch_cb;
4955 rfa.patch_arg = patch_arg;
4956 rfa.repo = repo;
4957 rfa.unlink_added_files = 0;
4958 TAILQ_FOREACH(pe, paths, entry) {
4959 err = worktree_status(worktree, pe->path, fileindex, repo,
4960 revert_file, &rfa, NULL, NULL, 1, 0);
4961 if (err)
4962 break;
4964 sync_err = sync_fileindex(fileindex, fileindex_path);
4965 if (sync_err && err == NULL)
4966 err = sync_err;
4967 done:
4968 free(fileindex_path);
4969 if (fileindex)
4970 got_fileindex_free(fileindex);
4971 unlockerr = lock_worktree(worktree, LOCK_SH);
4972 if (unlockerr && err == NULL)
4973 err = unlockerr;
4974 return err;
4977 static void
4978 free_commitable(struct got_commitable *ct)
4980 free(ct->path);
4981 free(ct->in_repo_path);
4982 free(ct->ondisk_path);
4983 free(ct->blob_id);
4984 free(ct->base_blob_id);
4985 free(ct->staged_blob_id);
4986 free(ct->base_commit_id);
4987 free(ct);
4990 struct collect_commitables_arg {
4991 struct got_pathlist_head *commitable_paths;
4992 struct got_repository *repo;
4993 struct got_worktree *worktree;
4994 struct got_fileindex *fileindex;
4995 int have_staged_files;
4996 int allow_bad_symlinks;
4997 int diff_header_shown;
4998 int commit_conflicts;
4999 FILE *diff_outfile;
5000 FILE *f1;
5001 FILE *f2;
5005 * Create a file which contains the target path of a symlink so we can feed
5006 * it as content to the diff engine.
5008 static const struct got_error *
5009 get_symlink_target_file(int *fd, int dirfd, const char *de_name,
5010 const char *abspath)
5012 const struct got_error *err = NULL;
5013 char target_path[PATH_MAX];
5014 ssize_t target_len, outlen;
5016 *fd = -1;
5018 if (dirfd != -1) {
5019 target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
5020 if (target_len == -1)
5021 return got_error_from_errno2("readlinkat", abspath);
5022 } else {
5023 target_len = readlink(abspath, target_path, PATH_MAX);
5024 if (target_len == -1)
5025 return got_error_from_errno2("readlink", abspath);
5028 *fd = got_opentempfd();
5029 if (*fd == -1)
5030 return got_error_from_errno("got_opentempfd");
5032 outlen = write(*fd, target_path, target_len);
5033 if (outlen == -1) {
5034 err = got_error_from_errno("got_opentempfd");
5035 goto done;
5038 if (lseek(*fd, 0, SEEK_SET) == -1) {
5039 err = got_error_from_errno2("lseek", abspath);
5040 goto done;
5042 done:
5043 if (err) {
5044 close(*fd);
5045 *fd = -1;
5047 return err;
5050 static const struct got_error *
5051 append_ct_diff(struct got_commitable *ct, int *diff_header_shown,
5052 FILE *diff_outfile, FILE *f1, FILE *f2, int dirfd, const char *de_name,
5053 int diff_staged, struct got_repository *repo, struct got_worktree *worktree)
5055 const struct got_error *err = NULL;
5056 struct got_blob_object *blob1 = NULL;
5057 int fd = -1, fd1 = -1, fd2 = -1;
5058 FILE *ondisk_file = NULL;
5059 char *label1 = NULL;
5060 struct stat sb;
5061 off_t size1 = 0;
5062 int f2_exists = 0;
5063 char *id_str = NULL;
5065 memset(&sb, 0, sizeof(sb));
5067 if (diff_staged) {
5068 if (ct->staged_status != GOT_STATUS_MODIFY &&
5069 ct->staged_status != GOT_STATUS_ADD &&
5070 ct->staged_status != GOT_STATUS_DELETE)
5071 return NULL;
5072 } else {
5073 if (ct->status != GOT_STATUS_MODIFY &&
5074 ct->status != GOT_STATUS_ADD &&
5075 ct->status != GOT_STATUS_DELETE &&
5076 ct->status != GOT_STATUS_CONFLICT)
5077 return NULL;
5080 err = got_opentemp_truncate(f1);
5081 if (err)
5082 return got_error_from_errno("got_opentemp_truncate");
5083 err = got_opentemp_truncate(f2);
5084 if (err)
5085 return got_error_from_errno("got_opentemp_truncate");
5087 if (!*diff_header_shown) {
5088 err = got_object_id_str(&id_str, worktree->base_commit_id);
5089 if (err)
5090 return err;
5091 fprintf(diff_outfile, "diff %s%s\n", diff_staged ? "-s " : "",
5092 got_worktree_get_root_path(worktree));
5093 fprintf(diff_outfile, "commit - %s\n", id_str);
5094 fprintf(diff_outfile, "path + %s%s\n",
5095 got_worktree_get_root_path(worktree),
5096 diff_staged ? " (staged changes)" : "");
5097 *diff_header_shown = 1;
5100 if (diff_staged) {
5101 const char *label1 = NULL, *label2 = NULL;
5102 switch (ct->staged_status) {
5103 case GOT_STATUS_MODIFY:
5104 label1 = ct->path;
5105 label2 = ct->path;
5106 break;
5107 case GOT_STATUS_ADD:
5108 label2 = ct->path;
5109 break;
5110 case GOT_STATUS_DELETE:
5111 label1 = ct->path;
5112 break;
5113 default:
5114 return got_error(GOT_ERR_FILE_STATUS);
5116 fd1 = got_opentempfd();
5117 if (fd1 == -1) {
5118 err = got_error_from_errno("got_opentempfd");
5119 goto done;
5121 fd2 = got_opentempfd();
5122 if (fd2 == -1) {
5123 err = got_error_from_errno("got_opentempfd");
5124 goto done;
5126 err = got_diff_objects_as_blobs(NULL, NULL, f1, f2,
5127 fd1, fd2, ct->base_blob_id, ct->staged_blob_id,
5128 label1, label2, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0,
5129 NULL, repo, diff_outfile);
5130 goto done;
5133 fd1 = got_opentempfd();
5134 if (fd1 == -1) {
5135 err = got_error_from_errno("got_opentempfd");
5136 goto done;
5139 if (ct->status != GOT_STATUS_ADD) {
5140 err = got_object_open_as_blob(&blob1, repo, ct->base_blob_id,
5141 8192, fd1);
5142 if (err)
5143 goto done;
5146 if (ct->status != GOT_STATUS_DELETE) {
5147 if (dirfd != -1) {
5148 fd = openat(dirfd, de_name,
5149 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
5150 if (fd == -1) {
5151 if (!got_err_open_nofollow_on_symlink()) {
5152 err = got_error_from_errno2("openat",
5153 ct->ondisk_path);
5154 goto done;
5156 err = get_symlink_target_file(&fd, dirfd,
5157 de_name, ct->ondisk_path);
5158 if (err)
5159 goto done;
5161 } else {
5162 fd = open(ct->ondisk_path,
5163 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
5164 if (fd == -1) {
5165 if (!got_err_open_nofollow_on_symlink()) {
5166 err = got_error_from_errno2("open",
5167 ct->ondisk_path);
5168 goto done;
5170 err = get_symlink_target_file(&fd, dirfd,
5171 de_name, ct->ondisk_path);
5172 if (err)
5173 goto done;
5176 if (fstatat(fd, ct->ondisk_path, &sb,
5177 AT_SYMLINK_NOFOLLOW) == -1) {
5178 err = got_error_from_errno2("fstatat", ct->ondisk_path);
5179 goto done;
5181 ondisk_file = fdopen(fd, "r");
5182 if (ondisk_file == NULL) {
5183 err = got_error_from_errno2("fdopen", ct->ondisk_path);
5184 goto done;
5186 fd = -1;
5187 f2_exists = 1;
5190 if (blob1) {
5191 err = got_object_blob_dump_to_file(&size1, NULL, NULL,
5192 f1, blob1);
5193 if (err)
5194 goto done;
5197 err = got_diff_blob_file(blob1, f1, size1, label1,
5198 ondisk_file ? ondisk_file : f2, f2_exists, &sb, ct->path,
5199 GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, diff_outfile);
5200 done:
5201 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
5202 err = got_error_from_errno("close");
5203 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
5204 err = got_error_from_errno("close");
5205 if (blob1)
5206 got_object_blob_close(blob1);
5207 if (fd != -1 && close(fd) == -1 && err == NULL)
5208 err = got_error_from_errno("close");
5209 if (ondisk_file && fclose(ondisk_file) == EOF && err == NULL)
5210 err = got_error_from_errno("fclose");
5211 return err;
5214 static const struct got_error *
5215 collect_commitables(void *arg, unsigned char status,
5216 unsigned char staged_status, const char *relpath,
5217 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
5218 struct got_object_id *commit_id, int dirfd, const char *de_name)
5220 struct collect_commitables_arg *a = arg;
5221 const struct got_error *err = NULL;
5222 struct got_commitable *ct = NULL;
5223 struct got_pathlist_entry *new = NULL;
5224 char *parent_path = NULL, *path = NULL;
5225 struct stat sb;
5227 if (a->have_staged_files) {
5228 if (staged_status != GOT_STATUS_MODIFY &&
5229 staged_status != GOT_STATUS_ADD &&
5230 staged_status != GOT_STATUS_DELETE)
5231 return NULL;
5232 } else {
5233 if (status == GOT_STATUS_CONFLICT && !a->commit_conflicts) {
5234 printf("C %s\n", relpath);
5235 return got_error(GOT_ERR_COMMIT_CONFLICT);
5238 if (status != GOT_STATUS_MODIFY &&
5239 status != GOT_STATUS_MODE_CHANGE &&
5240 status != GOT_STATUS_ADD &&
5241 status != GOT_STATUS_DELETE &&
5242 status != GOT_STATUS_CONFLICT)
5243 return NULL;
5246 if (asprintf(&path, "/%s", relpath) == -1) {
5247 err = got_error_from_errno("asprintf");
5248 goto done;
5250 if (strcmp(path, "/") == 0) {
5251 parent_path = strdup("");
5252 if (parent_path == NULL)
5253 return got_error_from_errno("strdup");
5254 } else {
5255 err = got_path_dirname(&parent_path, path);
5256 if (err)
5257 return err;
5260 ct = calloc(1, sizeof(*ct));
5261 if (ct == NULL) {
5262 err = got_error_from_errno("calloc");
5263 goto done;
5266 if (asprintf(&ct->ondisk_path, "%s/%s", a->worktree->root_path,
5267 relpath) == -1) {
5268 err = got_error_from_errno("asprintf");
5269 goto done;
5272 if (staged_status == GOT_STATUS_ADD ||
5273 staged_status == GOT_STATUS_MODIFY) {
5274 struct got_fileindex_entry *ie;
5275 ie = got_fileindex_entry_get(a->fileindex, path, strlen(path));
5276 switch (got_fileindex_entry_staged_filetype_get(ie)) {
5277 case GOT_FILEIDX_MODE_REGULAR_FILE:
5278 case GOT_FILEIDX_MODE_BAD_SYMLINK:
5279 ct->mode = S_IFREG;
5280 break;
5281 case GOT_FILEIDX_MODE_SYMLINK:
5282 ct->mode = S_IFLNK;
5283 break;
5284 default:
5285 err = got_error_path(path, GOT_ERR_BAD_FILETYPE);
5286 goto done;
5288 ct->mode |= got_fileindex_entry_perms_get(ie);
5289 } else if (status != GOT_STATUS_DELETE &&
5290 staged_status != GOT_STATUS_DELETE) {
5291 if (dirfd != -1) {
5292 if (fstatat(dirfd, de_name, &sb,
5293 AT_SYMLINK_NOFOLLOW) == -1) {
5294 err = got_error_from_errno2("fstatat",
5295 ct->ondisk_path);
5296 goto done;
5298 } else if (lstat(ct->ondisk_path, &sb) == -1) {
5299 err = got_error_from_errno2("lstat", ct->ondisk_path);
5300 goto done;
5302 ct->mode = sb.st_mode;
5305 if (asprintf(&ct->in_repo_path, "%s%s%s", a->worktree->path_prefix,
5306 got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/",
5307 relpath) == -1) {
5308 err = got_error_from_errno("asprintf");
5309 goto done;
5312 if (S_ISLNK(ct->mode) && staged_status == GOT_STATUS_NO_CHANGE &&
5313 status == GOT_STATUS_ADD && !a->allow_bad_symlinks) {
5314 int is_bad_symlink;
5315 char target_path[PATH_MAX];
5316 ssize_t target_len;
5317 target_len = readlink(ct->ondisk_path, target_path,
5318 sizeof(target_path));
5319 if (target_len == -1) {
5320 err = got_error_from_errno2("readlink",
5321 ct->ondisk_path);
5322 goto done;
5324 err = is_bad_symlink_target(&is_bad_symlink, target_path,
5325 target_len, ct->ondisk_path, a->worktree->root_path);
5326 if (err)
5327 goto done;
5328 if (is_bad_symlink) {
5329 err = got_error_path(ct->ondisk_path,
5330 GOT_ERR_BAD_SYMLINK);
5331 goto done;
5336 ct->status = status;
5337 ct->staged_status = staged_status;
5338 ct->blob_id = NULL; /* will be filled in when blob gets created */
5339 if (ct->status != GOT_STATUS_ADD &&
5340 ct->staged_status != GOT_STATUS_ADD) {
5341 ct->base_blob_id = got_object_id_dup(blob_id);
5342 if (ct->base_blob_id == NULL) {
5343 err = got_error_from_errno("got_object_id_dup");
5344 goto done;
5346 ct->base_commit_id = got_object_id_dup(commit_id);
5347 if (ct->base_commit_id == NULL) {
5348 err = got_error_from_errno("got_object_id_dup");
5349 goto done;
5352 if (ct->staged_status == GOT_STATUS_ADD ||
5353 ct->staged_status == GOT_STATUS_MODIFY) {
5354 ct->staged_blob_id = got_object_id_dup(staged_blob_id);
5355 if (ct->staged_blob_id == NULL) {
5356 err = got_error_from_errno("got_object_id_dup");
5357 goto done;
5360 ct->path = strdup(path);
5361 if (ct->path == NULL) {
5362 err = got_error_from_errno("strdup");
5363 goto done;
5365 err = got_pathlist_insert(&new, a->commitable_paths, ct->path, ct);
5366 if (err)
5367 goto done;
5369 if (a->diff_outfile && ct && new != NULL) {
5370 err = append_ct_diff(ct, &a->diff_header_shown,
5371 a->diff_outfile, a->f1, a->f2, dirfd, de_name,
5372 a->have_staged_files, a->repo, a->worktree);
5373 if (err)
5374 goto done;
5376 done:
5377 if (ct && (err || new == NULL))
5378 free_commitable(ct);
5379 free(parent_path);
5380 free(path);
5381 return err;
5384 static const struct got_error *write_tree(struct got_object_id **, int *,
5385 struct got_tree_object *, const char *, struct got_pathlist_head *,
5386 got_worktree_status_cb status_cb, void *status_arg,
5387 struct got_repository *);
5389 static const struct got_error *
5390 write_subtree(struct got_object_id **new_subtree_id, int *nentries,
5391 struct got_tree_entry *te, const char *parent_path,
5392 struct got_pathlist_head *commitable_paths,
5393 got_worktree_status_cb status_cb, void *status_arg,
5394 struct got_repository *repo)
5396 const struct got_error *err = NULL;
5397 struct got_tree_object *subtree;
5398 char *subpath;
5400 if (asprintf(&subpath, "%s%s%s", parent_path,
5401 got_path_is_root_dir(parent_path) ? "" : "/", te->name) == -1)
5402 return got_error_from_errno("asprintf");
5404 err = got_object_open_as_tree(&subtree, repo, &te->id);
5405 if (err)
5406 return err;
5408 err = write_tree(new_subtree_id, nentries, subtree, subpath,
5409 commitable_paths, status_cb, status_arg, repo);
5410 got_object_tree_close(subtree);
5411 free(subpath);
5412 return err;
5415 static const struct got_error *
5416 match_ct_parent_path(int *match, struct got_commitable *ct, const char *path)
5418 const struct got_error *err = NULL;
5419 char *ct_parent_path = NULL;
5421 *match = 0;
5423 if (strchr(ct->in_repo_path, '/') == NULL) {
5424 *match = got_path_is_root_dir(path);
5425 return NULL;
5428 err = got_path_dirname(&ct_parent_path, ct->in_repo_path);
5429 if (err)
5430 return err;
5431 *match = (strcmp(path, ct_parent_path) == 0);
5432 free(ct_parent_path);
5433 return err;
5436 static mode_t
5437 get_ct_file_mode(struct got_commitable *ct)
5439 if (S_ISLNK(ct->mode))
5440 return S_IFLNK;
5442 return S_IFREG | (ct->mode & ((S_IRWXU | S_IRWXG | S_IRWXO)));
5445 static const struct got_error *
5446 alloc_modified_blob_tree_entry(struct got_tree_entry **new_te,
5447 struct got_tree_entry *te, struct got_commitable *ct)
5449 const struct got_error *err = NULL;
5451 *new_te = NULL;
5453 err = got_object_tree_entry_dup(new_te, te);
5454 if (err)
5455 goto done;
5457 (*new_te)->mode = get_ct_file_mode(ct);
5459 if (ct->staged_status == GOT_STATUS_MODIFY)
5460 memcpy(&(*new_te)->id, ct->staged_blob_id,
5461 sizeof((*new_te)->id));
5462 else
5463 memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id));
5464 done:
5465 if (err && *new_te) {
5466 free(*new_te);
5467 *new_te = NULL;
5469 return err;
5472 static const struct got_error *
5473 alloc_added_blob_tree_entry(struct got_tree_entry **new_te,
5474 struct got_commitable *ct)
5476 const struct got_error *err = NULL;
5477 char *ct_name = NULL;
5479 *new_te = NULL;
5481 *new_te = calloc(1, sizeof(**new_te));
5482 if (*new_te == NULL)
5483 return got_error_from_errno("calloc");
5485 err = got_path_basename(&ct_name, ct->path);
5486 if (err)
5487 goto done;
5488 if (strlcpy((*new_te)->name, ct_name, sizeof((*new_te)->name)) >=
5489 sizeof((*new_te)->name)) {
5490 err = got_error(GOT_ERR_NO_SPACE);
5491 goto done;
5494 (*new_te)->mode = get_ct_file_mode(ct);
5496 if (ct->staged_status == GOT_STATUS_ADD)
5497 memcpy(&(*new_te)->id, ct->staged_blob_id,
5498 sizeof((*new_te)->id));
5499 else
5500 memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id));
5501 done:
5502 free(ct_name);
5503 if (err && *new_te) {
5504 free(*new_te);
5505 *new_te = NULL;
5507 return err;
5510 static const struct got_error *
5511 insert_tree_entry(struct got_tree_entry *new_te,
5512 struct got_pathlist_head *paths)
5514 const struct got_error *err = NULL;
5515 struct got_pathlist_entry *new_pe;
5517 err = got_pathlist_insert(&new_pe, paths, new_te->name, new_te);
5518 if (err)
5519 return err;
5520 if (new_pe == NULL)
5521 return got_error(GOT_ERR_TREE_DUP_ENTRY);
5522 return NULL;
5525 static const struct got_error *
5526 report_ct_status(struct got_commitable *ct,
5527 got_worktree_status_cb status_cb, void *status_arg)
5529 const char *ct_path = ct->path;
5530 unsigned char status;
5532 if (status_cb == NULL) /* no commit progress output desired */
5533 return NULL;
5535 while (ct_path[0] == '/')
5536 ct_path++;
5538 if (ct->staged_status != GOT_STATUS_NO_CHANGE)
5539 status = ct->staged_status;
5540 else
5541 status = ct->status;
5543 return (*status_cb)(status_arg, status, GOT_STATUS_NO_CHANGE,
5544 ct_path, ct->blob_id, NULL, NULL, -1, NULL);
5547 static const struct got_error *
5548 match_modified_subtree(int *modified, struct got_tree_entry *te,
5549 const char *base_tree_path, struct got_pathlist_head *commitable_paths)
5551 const struct got_error *err = NULL;
5552 struct got_pathlist_entry *pe;
5553 char *te_path;
5555 *modified = 0;
5557 if (asprintf(&te_path, "%s%s%s", base_tree_path,
5558 got_path_is_root_dir(base_tree_path) ? "" : "/",
5559 te->name) == -1)
5560 return got_error_from_errno("asprintf");
5562 TAILQ_FOREACH(pe, commitable_paths, entry) {
5563 struct got_commitable *ct = pe->data;
5564 *modified = got_path_is_child(ct->in_repo_path, te_path,
5565 strlen(te_path));
5566 if (*modified)
5567 break;
5570 free(te_path);
5571 return err;
5574 static const struct got_error *
5575 match_deleted_or_modified_ct(struct got_commitable **ctp,
5576 struct got_tree_entry *te, const char *base_tree_path,
5577 struct got_pathlist_head *commitable_paths)
5579 const struct got_error *err = NULL;
5580 struct got_pathlist_entry *pe;
5582 *ctp = NULL;
5584 TAILQ_FOREACH(pe, commitable_paths, entry) {
5585 struct got_commitable *ct = pe->data;
5586 char *ct_name = NULL;
5587 int path_matches;
5589 if (ct->staged_status == GOT_STATUS_NO_CHANGE) {
5590 if (ct->status != GOT_STATUS_MODIFY &&
5591 ct->status != GOT_STATUS_MODE_CHANGE &&
5592 ct->status != GOT_STATUS_DELETE &&
5593 ct->status != GOT_STATUS_CONFLICT)
5594 continue;
5595 } else {
5596 if (ct->staged_status != GOT_STATUS_MODIFY &&
5597 ct->staged_status != GOT_STATUS_DELETE)
5598 continue;
5601 if (got_object_id_cmp(ct->base_blob_id, &te->id) != 0)
5602 continue;
5604 err = match_ct_parent_path(&path_matches, ct, base_tree_path);
5605 if (err)
5606 return err;
5607 if (!path_matches)
5608 continue;
5610 err = got_path_basename(&ct_name, pe->path);
5611 if (err)
5612 return err;
5614 if (strcmp(te->name, ct_name) != 0) {
5615 free(ct_name);
5616 continue;
5618 free(ct_name);
5620 *ctp = ct;
5621 break;
5624 return err;
5627 static const struct got_error *
5628 make_subtree_for_added_blob(struct got_tree_entry **new_tep,
5629 const char *child_path, const char *path_base_tree,
5630 struct got_pathlist_head *commitable_paths,
5631 got_worktree_status_cb status_cb, void *status_arg,
5632 struct got_repository *repo)
5634 const struct got_error *err = NULL;
5635 struct got_tree_entry *new_te;
5636 char *subtree_path;
5637 struct got_object_id *id = NULL;
5638 int nentries;
5640 *new_tep = NULL;
5642 if (asprintf(&subtree_path, "%s%s%s", path_base_tree,
5643 got_path_is_root_dir(path_base_tree) ? "" : "/",
5644 child_path) == -1)
5645 return got_error_from_errno("asprintf");
5647 new_te = calloc(1, sizeof(*new_te));
5648 if (new_te == NULL)
5649 return got_error_from_errno("calloc");
5650 new_te->mode = S_IFDIR;
5652 if (strlcpy(new_te->name, child_path, sizeof(new_te->name)) >=
5653 sizeof(new_te->name)) {
5654 err = got_error(GOT_ERR_NO_SPACE);
5655 goto done;
5657 err = write_tree(&id, &nentries, NULL, subtree_path,
5658 commitable_paths, status_cb, status_arg, repo);
5659 if (err) {
5660 free(new_te);
5661 goto done;
5663 memcpy(&new_te->id, id, sizeof(new_te->id));
5664 done:
5665 free(id);
5666 free(subtree_path);
5667 if (err == NULL)
5668 *new_tep = new_te;
5669 return err;
5672 static const struct got_error *
5673 write_tree(struct got_object_id **new_tree_id, int *nentries,
5674 struct got_tree_object *base_tree, const char *path_base_tree,
5675 struct got_pathlist_head *commitable_paths,
5676 got_worktree_status_cb status_cb, void *status_arg,
5677 struct got_repository *repo)
5679 const struct got_error *err = NULL;
5680 struct got_pathlist_head paths;
5681 struct got_tree_entry *te, *new_te = NULL;
5682 struct got_pathlist_entry *pe;
5684 TAILQ_INIT(&paths);
5685 *nentries = 0;
5687 /* Insert, and recurse into, newly added entries first. */
5688 TAILQ_FOREACH(pe, commitable_paths, entry) {
5689 struct got_commitable *ct = pe->data;
5690 char *child_path = NULL, *slash;
5692 if ((ct->status != GOT_STATUS_ADD &&
5693 ct->staged_status != GOT_STATUS_ADD) ||
5694 (ct->flags & GOT_COMMITABLE_ADDED))
5695 continue;
5697 if (!got_path_is_child(ct->in_repo_path, path_base_tree,
5698 strlen(path_base_tree)))
5699 continue;
5701 err = got_path_skip_common_ancestor(&child_path, path_base_tree,
5702 ct->in_repo_path);
5703 if (err)
5704 goto done;
5706 slash = strchr(child_path, '/');
5707 if (slash == NULL) {
5708 err = alloc_added_blob_tree_entry(&new_te, ct);
5709 if (err)
5710 goto done;
5711 err = report_ct_status(ct, status_cb, status_arg);
5712 if (err)
5713 goto done;
5714 ct->flags |= GOT_COMMITABLE_ADDED;
5715 err = insert_tree_entry(new_te, &paths);
5716 if (err)
5717 goto done;
5718 (*nentries)++;
5719 } else {
5720 *slash = '\0'; /* trim trailing path components */
5721 if (base_tree == NULL ||
5722 got_object_tree_find_entry(base_tree, child_path)
5723 == NULL) {
5724 err = make_subtree_for_added_blob(&new_te,
5725 child_path, path_base_tree,
5726 commitable_paths, status_cb, status_arg,
5727 repo);
5728 if (err)
5729 goto done;
5730 err = insert_tree_entry(new_te, &paths);
5731 if (err)
5732 goto done;
5733 (*nentries)++;
5738 if (base_tree) {
5739 int i, nbase_entries;
5740 /* Handle modified and deleted entries. */
5741 nbase_entries = got_object_tree_get_nentries(base_tree);
5742 for (i = 0; i < nbase_entries; i++) {
5743 struct got_commitable *ct = NULL;
5745 te = got_object_tree_get_entry(base_tree, i);
5746 if (got_object_tree_entry_is_submodule(te)) {
5747 /* Entry is a submodule; just copy it. */
5748 err = got_object_tree_entry_dup(&new_te, te);
5749 if (err)
5750 goto done;
5751 err = insert_tree_entry(new_te, &paths);
5752 if (err)
5753 goto done;
5754 (*nentries)++;
5755 continue;
5758 if (S_ISDIR(te->mode)) {
5759 int modified;
5760 err = got_object_tree_entry_dup(&new_te, te);
5761 if (err)
5762 goto done;
5763 err = match_modified_subtree(&modified, te,
5764 path_base_tree, commitable_paths);
5765 if (err)
5766 goto done;
5767 /* Avoid recursion into unmodified subtrees. */
5768 if (modified) {
5769 struct got_object_id *new_id;
5770 int nsubentries;
5771 err = write_subtree(&new_id,
5772 &nsubentries, te,
5773 path_base_tree, commitable_paths,
5774 status_cb, status_arg, repo);
5775 if (err)
5776 goto done;
5777 if (nsubentries == 0) {
5778 /* All entries were deleted. */
5779 free(new_id);
5780 continue;
5782 memcpy(&new_te->id, new_id,
5783 sizeof(new_te->id));
5784 free(new_id);
5786 err = insert_tree_entry(new_te, &paths);
5787 if (err)
5788 goto done;
5789 (*nentries)++;
5790 continue;
5793 err = match_deleted_or_modified_ct(&ct, te,
5794 path_base_tree, commitable_paths);
5795 if (err)
5796 goto done;
5797 if (ct) {
5798 /* NB: Deleted entries get dropped here. */
5799 if (ct->status == GOT_STATUS_MODIFY ||
5800 ct->status == GOT_STATUS_MODE_CHANGE ||
5801 ct->status == GOT_STATUS_CONFLICT ||
5802 ct->staged_status == GOT_STATUS_MODIFY) {
5803 err = alloc_modified_blob_tree_entry(
5804 &new_te, te, ct);
5805 if (err)
5806 goto done;
5807 err = insert_tree_entry(new_te, &paths);
5808 if (err)
5809 goto done;
5810 (*nentries)++;
5812 err = report_ct_status(ct, status_cb,
5813 status_arg);
5814 if (err)
5815 goto done;
5816 } else {
5817 /* Entry is unchanged; just copy it. */
5818 err = got_object_tree_entry_dup(&new_te, te);
5819 if (err)
5820 goto done;
5821 err = insert_tree_entry(new_te, &paths);
5822 if (err)
5823 goto done;
5824 (*nentries)++;
5829 /* Write new list of entries; deleted entries have been dropped. */
5830 err = got_object_tree_create(new_tree_id, &paths, *nentries, repo);
5831 done:
5832 got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
5833 return err;
5836 static const struct got_error *
5837 update_fileindex_after_commit(struct got_worktree *worktree,
5838 struct got_pathlist_head *commitable_paths,
5839 struct got_object_id *new_base_commit_id,
5840 struct got_fileindex *fileindex, int have_staged_files)
5842 const struct got_error *err = NULL;
5843 struct got_pathlist_entry *pe;
5844 char *relpath = NULL;
5846 TAILQ_FOREACH(pe, commitable_paths, entry) {
5847 struct got_fileindex_entry *ie;
5848 struct got_commitable *ct = pe->data;
5850 ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len);
5852 err = got_path_skip_common_ancestor(&relpath,
5853 worktree->root_path, ct->ondisk_path);
5854 if (err)
5855 goto done;
5857 if (ie) {
5858 if (ct->status == GOT_STATUS_DELETE ||
5859 ct->staged_status == GOT_STATUS_DELETE) {
5860 got_fileindex_entry_remove(fileindex, ie);
5861 } else if (ct->staged_status == GOT_STATUS_ADD ||
5862 ct->staged_status == GOT_STATUS_MODIFY) {
5863 got_fileindex_entry_stage_set(ie,
5864 GOT_FILEIDX_STAGE_NONE);
5865 got_fileindex_entry_staged_filetype_set(ie, 0);
5867 err = got_fileindex_entry_update(ie,
5868 worktree->root_fd, relpath,
5869 ct->staged_blob_id->sha1,
5870 new_base_commit_id->sha1,
5871 !have_staged_files);
5872 } else
5873 err = got_fileindex_entry_update(ie,
5874 worktree->root_fd, relpath,
5875 ct->blob_id->sha1,
5876 new_base_commit_id->sha1,
5877 !have_staged_files);
5878 } else {
5879 err = got_fileindex_entry_alloc(&ie, pe->path);
5880 if (err)
5881 goto done;
5882 err = got_fileindex_entry_update(ie,
5883 worktree->root_fd, relpath, ct->blob_id->sha1,
5884 new_base_commit_id->sha1, 1);
5885 if (err) {
5886 got_fileindex_entry_free(ie);
5887 goto done;
5889 err = got_fileindex_entry_add(fileindex, ie);
5890 if (err) {
5891 got_fileindex_entry_free(ie);
5892 goto done;
5895 free(relpath);
5896 relpath = NULL;
5898 done:
5899 free(relpath);
5900 return err;
5904 static const struct got_error *
5905 check_out_of_date(const char *in_repo_path, unsigned char status,
5906 unsigned char staged_status, struct got_object_id *base_blob_id,
5907 struct got_object_id *base_commit_id,
5908 struct got_object_id *head_commit_id, struct got_repository *repo,
5909 int ood_errcode)
5911 const struct got_error *err = NULL;
5912 struct got_commit_object *commit = NULL;
5913 struct got_object_id *id = NULL;
5915 if (status != GOT_STATUS_ADD && staged_status != GOT_STATUS_ADD) {
5916 /* Trivial case: base commit == head commit */
5917 if (got_object_id_cmp(base_commit_id, head_commit_id) == 0)
5918 return NULL;
5920 * Ensure file content which local changes were based
5921 * on matches file content in the branch head.
5923 err = got_object_open_as_commit(&commit, repo, head_commit_id);
5924 if (err)
5925 goto done;
5926 err = got_object_id_by_path(&id, repo, commit, in_repo_path);
5927 if (err) {
5928 if (err->code == GOT_ERR_NO_TREE_ENTRY)
5929 err = got_error(ood_errcode);
5930 goto done;
5931 } else if (got_object_id_cmp(id, base_blob_id) != 0)
5932 err = got_error(ood_errcode);
5933 } else {
5934 /* Require that added files don't exist in the branch head. */
5935 err = got_object_open_as_commit(&commit, repo, head_commit_id);
5936 if (err)
5937 goto done;
5938 err = got_object_id_by_path(&id, repo, commit, in_repo_path);
5939 if (err && err->code != GOT_ERR_NO_TREE_ENTRY)
5940 goto done;
5941 err = id ? got_error(ood_errcode) : NULL;
5943 done:
5944 free(id);
5945 if (commit)
5946 got_object_commit_close(commit);
5947 return err;
5950 static const struct got_error *
5951 commit_worktree(struct got_object_id **new_commit_id,
5952 struct got_pathlist_head *commitable_paths,
5953 struct got_object_id *head_commit_id,
5954 struct got_object_id *parent_id2,
5955 struct got_worktree *worktree,
5956 const char *author, const char *committer, char *diff_path,
5957 got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
5958 got_worktree_status_cb status_cb, void *status_arg,
5959 struct got_repository *repo)
5961 const struct got_error *err = NULL, *unlockerr = NULL;
5962 struct got_pathlist_entry *pe;
5963 const char *head_ref_name = NULL;
5964 struct got_commit_object *head_commit = NULL;
5965 struct got_reference *head_ref2 = NULL;
5966 struct got_object_id *head_commit_id2 = NULL;
5967 struct got_tree_object *head_tree = NULL;
5968 struct got_object_id *new_tree_id = NULL;
5969 int nentries, nparents = 0;
5970 struct got_object_id_queue parent_ids;
5971 struct got_object_qid *pid = NULL;
5972 char *logmsg = NULL;
5973 time_t timestamp;
5975 *new_commit_id = NULL;
5977 STAILQ_INIT(&parent_ids);
5979 err = got_object_open_as_commit(&head_commit, repo, head_commit_id);
5980 if (err)
5981 goto done;
5983 err = got_object_open_as_tree(&head_tree, repo, head_commit->tree_id);
5984 if (err)
5985 goto done;
5987 if (commit_msg_cb != NULL) {
5988 err = commit_msg_cb(commitable_paths, diff_path,
5989 &logmsg, commit_arg);
5990 if (err)
5991 goto done;
5994 if (logmsg == NULL || strlen(logmsg) == 0) {
5995 err = got_error(GOT_ERR_COMMIT_MSG_EMPTY);
5996 goto done;
5999 /* Create blobs from added and modified files and record their IDs. */
6000 TAILQ_FOREACH(pe, commitable_paths, entry) {
6001 struct got_commitable *ct = pe->data;
6002 char *ondisk_path;
6004 /* Blobs for staged files already exist. */
6005 if (ct->staged_status == GOT_STATUS_ADD ||
6006 ct->staged_status == GOT_STATUS_MODIFY)
6007 continue;
6009 if (ct->status != GOT_STATUS_ADD &&
6010 ct->status != GOT_STATUS_MODIFY &&
6011 ct->status != GOT_STATUS_MODE_CHANGE &&
6012 ct->status != GOT_STATUS_CONFLICT)
6013 continue;
6015 if (asprintf(&ondisk_path, "%s/%s",
6016 worktree->root_path, pe->path) == -1) {
6017 err = got_error_from_errno("asprintf");
6018 goto done;
6020 err = got_object_blob_create(&ct->blob_id, ondisk_path, repo);
6021 free(ondisk_path);
6022 if (err)
6023 goto done;
6026 /* Recursively write new tree objects. */
6027 err = write_tree(&new_tree_id, &nentries, head_tree, "/",
6028 commitable_paths, status_cb, status_arg, repo);
6029 if (err)
6030 goto done;
6032 err = got_object_qid_alloc(&pid, worktree->base_commit_id);
6033 if (err)
6034 goto done;
6035 STAILQ_INSERT_TAIL(&parent_ids, pid, entry);
6036 nparents++;
6037 if (parent_id2) {
6038 err = got_object_qid_alloc(&pid, parent_id2);
6039 if (err)
6040 goto done;
6041 STAILQ_INSERT_TAIL(&parent_ids, pid, entry);
6042 nparents++;
6044 timestamp = time(NULL);
6045 err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids,
6046 nparents, author, timestamp, committer, timestamp, logmsg, repo);
6047 if (logmsg != NULL)
6048 free(logmsg);
6049 if (err)
6050 goto done;
6052 /* Check if a concurrent commit to our branch has occurred. */
6053 head_ref_name = got_worktree_get_head_ref_name(worktree);
6054 if (head_ref_name == NULL) {
6055 err = got_error_from_errno("got_worktree_get_head_ref_name");
6056 goto done;
6058 /* Lock the reference here to prevent concurrent modification. */
6059 err = got_ref_open(&head_ref2, repo, head_ref_name, 1);
6060 if (err)
6061 goto done;
6062 err = got_ref_resolve(&head_commit_id2, repo, head_ref2);
6063 if (err)
6064 goto done;
6065 if (got_object_id_cmp(head_commit_id, head_commit_id2) != 0) {
6066 err = got_error(GOT_ERR_COMMIT_HEAD_CHANGED);
6067 goto done;
6069 /* Update branch head in repository. */
6070 err = got_ref_change_ref(head_ref2, *new_commit_id);
6071 if (err)
6072 goto done;
6073 err = got_ref_write(head_ref2, repo);
6074 if (err)
6075 goto done;
6077 err = got_worktree_set_base_commit_id(worktree, repo, *new_commit_id);
6078 if (err)
6079 goto done;
6081 err = ref_base_commit(worktree, repo);
6082 if (err)
6083 goto done;
6084 done:
6085 got_object_id_queue_free(&parent_ids);
6086 if (head_tree)
6087 got_object_tree_close(head_tree);
6088 if (head_commit)
6089 got_object_commit_close(head_commit);
6090 free(head_commit_id2);
6091 if (head_ref2) {
6092 unlockerr = got_ref_unlock(head_ref2);
6093 if (unlockerr && err == NULL)
6094 err = unlockerr;
6095 got_ref_close(head_ref2);
6097 return err;
6100 static const struct got_error *
6101 check_path_is_commitable(const char *path,
6102 struct got_pathlist_head *commitable_paths)
6104 struct got_pathlist_entry *cpe = NULL;
6105 size_t path_len = strlen(path);
6107 TAILQ_FOREACH(cpe, commitable_paths, entry) {
6108 struct got_commitable *ct = cpe->data;
6109 const char *ct_path = ct->path;
6111 while (ct_path[0] == '/')
6112 ct_path++;
6114 if (strcmp(path, ct_path) == 0 ||
6115 got_path_is_child(ct_path, path, path_len))
6116 break;
6119 if (cpe == NULL)
6120 return got_error_path(path, GOT_ERR_BAD_PATH);
6122 return NULL;
6125 static const struct got_error *
6126 check_staged_file(void *arg, struct got_fileindex_entry *ie)
6128 int *have_staged_files = arg;
6130 if (got_fileindex_entry_stage_get(ie) != GOT_FILEIDX_STAGE_NONE) {
6131 *have_staged_files = 1;
6132 return got_error(GOT_ERR_CANCELLED);
6135 return NULL;
6138 static const struct got_error *
6139 check_non_staged_files(struct got_fileindex *fileindex,
6140 struct got_pathlist_head *paths)
6142 struct got_pathlist_entry *pe;
6143 struct got_fileindex_entry *ie;
6145 TAILQ_FOREACH(pe, paths, entry) {
6146 if (pe->path[0] == '\0')
6147 continue;
6148 ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len);
6149 if (ie == NULL)
6150 return got_error_path(pe->path, GOT_ERR_BAD_PATH);
6151 if (got_fileindex_entry_stage_get(ie) == GOT_FILEIDX_STAGE_NONE)
6152 return got_error_path(pe->path,
6153 GOT_ERR_FILE_NOT_STAGED);
6156 return NULL;
6159 const struct got_error *
6160 got_worktree_commit(struct got_object_id **new_commit_id,
6161 struct got_worktree *worktree, struct got_pathlist_head *paths,
6162 const char *author, const char *committer, int allow_bad_symlinks,
6163 int show_diff, int commit_conflicts,
6164 got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
6165 got_worktree_status_cb status_cb, void *status_arg,
6166 struct got_repository *repo)
6168 const struct got_error *err = NULL, *unlockerr = NULL, *sync_err;
6169 struct got_fileindex *fileindex = NULL;
6170 char *fileindex_path = NULL;
6171 struct got_pathlist_head commitable_paths;
6172 struct collect_commitables_arg cc_arg;
6173 struct got_pathlist_entry *pe;
6174 struct got_reference *head_ref = NULL;
6175 struct got_object_id *head_commit_id = NULL;
6176 char *diff_path = NULL;
6177 int have_staged_files = 0;
6179 *new_commit_id = NULL;
6181 memset(&cc_arg, 0, sizeof(cc_arg));
6182 TAILQ_INIT(&commitable_paths);
6184 err = lock_worktree(worktree, LOCK_EX);
6185 if (err)
6186 goto done;
6188 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
6189 if (err)
6190 goto done;
6192 err = got_ref_resolve(&head_commit_id, repo, head_ref);
6193 if (err)
6194 goto done;
6196 err = open_fileindex(&fileindex, &fileindex_path, worktree);
6197 if (err)
6198 goto done;
6200 err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file,
6201 &have_staged_files);
6202 if (err && err->code != GOT_ERR_CANCELLED)
6203 goto done;
6204 if (have_staged_files) {
6205 err = check_non_staged_files(fileindex, paths);
6206 if (err)
6207 goto done;
6210 cc_arg.commitable_paths = &commitable_paths;
6211 cc_arg.worktree = worktree;
6212 cc_arg.fileindex = fileindex;
6213 cc_arg.repo = repo;
6214 cc_arg.have_staged_files = have_staged_files;
6215 cc_arg.allow_bad_symlinks = allow_bad_symlinks;
6216 cc_arg.diff_header_shown = 0;
6217 cc_arg.commit_conflicts = commit_conflicts;
6218 if (show_diff) {
6219 err = got_opentemp_named(&diff_path, &cc_arg.diff_outfile,
6220 GOT_TMPDIR_STR "/got", ".diff");
6221 if (err)
6222 goto done;
6223 cc_arg.f1 = got_opentemp();
6224 if (cc_arg.f1 == NULL) {
6225 err = got_error_from_errno("got_opentemp");
6226 goto done;
6228 cc_arg.f2 = got_opentemp();
6229 if (cc_arg.f2 == NULL) {
6230 err = got_error_from_errno("got_opentemp");
6231 goto done;
6235 TAILQ_FOREACH(pe, paths, entry) {
6236 err = worktree_status(worktree, pe->path, fileindex, repo,
6237 collect_commitables, &cc_arg, NULL, NULL, 0, 0);
6238 if (err)
6239 goto done;
6242 if (show_diff) {
6243 if (fflush(cc_arg.diff_outfile) == EOF) {
6244 err = got_error_from_errno("fflush");
6245 goto done;
6249 if (TAILQ_EMPTY(&commitable_paths)) {
6250 err = got_error(GOT_ERR_COMMIT_NO_CHANGES);
6251 goto done;
6254 TAILQ_FOREACH(pe, paths, entry) {
6255 err = check_path_is_commitable(pe->path, &commitable_paths);
6256 if (err)
6257 goto done;
6260 TAILQ_FOREACH(pe, &commitable_paths, entry) {
6261 struct got_commitable *ct = pe->data;
6262 const char *ct_path = ct->in_repo_path;
6264 while (ct_path[0] == '/')
6265 ct_path++;
6266 err = check_out_of_date(ct_path, ct->status,
6267 ct->staged_status, ct->base_blob_id, ct->base_commit_id,
6268 head_commit_id, repo, GOT_ERR_COMMIT_OUT_OF_DATE);
6269 if (err)
6270 goto done;
6274 err = commit_worktree(new_commit_id, &commitable_paths,
6275 head_commit_id, NULL, worktree, author, committer,
6276 (diff_path && cc_arg.diff_header_shown) ? diff_path : NULL,
6277 commit_msg_cb, commit_arg, status_cb, status_arg, repo);
6278 if (err)
6279 goto done;
6281 err = update_fileindex_after_commit(worktree, &commitable_paths,
6282 *new_commit_id, fileindex, have_staged_files);
6283 sync_err = sync_fileindex(fileindex, fileindex_path);
6284 if (sync_err && err == NULL)
6285 err = sync_err;
6286 done:
6287 if (fileindex)
6288 got_fileindex_free(fileindex);
6289 free(fileindex_path);
6290 unlockerr = lock_worktree(worktree, LOCK_SH);
6291 if (unlockerr && err == NULL)
6292 err = unlockerr;
6293 TAILQ_FOREACH(pe, &commitable_paths, entry) {
6294 struct got_commitable *ct = pe->data;
6296 free_commitable(ct);
6298 got_pathlist_free(&commitable_paths, GOT_PATHLIST_FREE_NONE);
6299 if (diff_path && unlink(diff_path) == -1 && err == NULL)
6300 err = got_error_from_errno2("unlink", diff_path);
6301 free(diff_path);
6302 if (cc_arg.diff_outfile && fclose(cc_arg.diff_outfile) == EOF &&
6303 err == NULL)
6304 err = got_error_from_errno("fclose");
6305 return err;
6308 const char *
6309 got_commitable_get_path(struct got_commitable *ct)
6311 return ct->path;
6314 unsigned int
6315 got_commitable_get_status(struct got_commitable *ct)
6317 return ct->status;
6320 struct check_rebase_ok_arg {
6321 struct got_worktree *worktree;
6322 struct got_repository *repo;
6325 static const struct got_error *
6326 check_rebase_ok(void *arg, struct got_fileindex_entry *ie)
6328 const struct got_error *err = NULL;
6329 struct check_rebase_ok_arg *a = arg;
6330 unsigned char status;
6331 struct stat sb;
6332 char *ondisk_path;
6334 /* Reject rebase of a work tree with mixed base commits. */
6335 if (memcmp(ie->commit_sha1, a->worktree->base_commit_id->sha1,
6336 SHA1_DIGEST_LENGTH))
6337 return got_error(GOT_ERR_MIXED_COMMITS);
6339 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path)
6340 == -1)
6341 return got_error_from_errno("asprintf");
6343 /* Reject rebase of a work tree with modified or staged files. */
6344 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
6345 free(ondisk_path);
6346 if (err)
6347 return err;
6349 if (status != GOT_STATUS_NO_CHANGE)
6350 return got_error(GOT_ERR_MODIFIED);
6351 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE)
6352 return got_error_path(ie->path, GOT_ERR_FILE_STAGED);
6354 return NULL;
6357 const struct got_error *
6358 got_worktree_rebase_prepare(struct got_reference **new_base_branch_ref,
6359 struct got_reference **tmp_branch, struct got_fileindex **fileindex,
6360 struct got_worktree *worktree, struct got_reference *branch,
6361 struct got_repository *repo)
6363 const struct got_error *err = NULL;
6364 char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL;
6365 char *branch_ref_name = NULL;
6366 char *fileindex_path = NULL;
6367 struct check_rebase_ok_arg ok_arg;
6368 struct got_reference *wt_branch = NULL, *branch_ref = NULL;
6369 struct got_object_id *wt_branch_tip = NULL;
6371 *new_base_branch_ref = NULL;
6372 *tmp_branch = NULL;
6373 *fileindex = NULL;
6375 err = lock_worktree(worktree, LOCK_EX);
6376 if (err)
6377 return err;
6379 err = open_fileindex(fileindex, &fileindex_path, worktree);
6380 if (err)
6381 goto done;
6383 ok_arg.worktree = worktree;
6384 ok_arg.repo = repo;
6385 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
6386 &ok_arg);
6387 if (err)
6388 goto done;
6390 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
6391 if (err)
6392 goto done;
6394 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
6395 if (err)
6396 goto done;
6398 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
6399 if (err)
6400 goto done;
6402 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
6403 0);
6404 if (err)
6405 goto done;
6407 err = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
6408 if (err)
6409 goto done;
6410 if (got_object_id_cmp(worktree->base_commit_id, wt_branch_tip) != 0) {
6411 err = got_error(GOT_ERR_REBASE_OUT_OF_DATE);
6412 goto done;
6415 err = got_ref_alloc_symref(new_base_branch_ref,
6416 new_base_branch_ref_name, wt_branch);
6417 if (err)
6418 goto done;
6419 err = got_ref_write(*new_base_branch_ref, repo);
6420 if (err)
6421 goto done;
6423 /* TODO Lock original branch's ref while rebasing? */
6425 err = got_ref_alloc_symref(&branch_ref, branch_ref_name, branch);
6426 if (err)
6427 goto done;
6429 err = got_ref_write(branch_ref, repo);
6430 if (err)
6431 goto done;
6433 err = got_ref_alloc(tmp_branch, tmp_branch_name,
6434 worktree->base_commit_id);
6435 if (err)
6436 goto done;
6437 err = got_ref_write(*tmp_branch, repo);
6438 if (err)
6439 goto done;
6441 err = got_worktree_set_head_ref(worktree, *tmp_branch);
6442 if (err)
6443 goto done;
6444 done:
6445 free(fileindex_path);
6446 free(tmp_branch_name);
6447 free(new_base_branch_ref_name);
6448 free(branch_ref_name);
6449 if (branch_ref)
6450 got_ref_close(branch_ref);
6451 if (wt_branch)
6452 got_ref_close(wt_branch);
6453 free(wt_branch_tip);
6454 if (err) {
6455 if (*new_base_branch_ref) {
6456 got_ref_close(*new_base_branch_ref);
6457 *new_base_branch_ref = NULL;
6459 if (*tmp_branch) {
6460 got_ref_close(*tmp_branch);
6461 *tmp_branch = NULL;
6463 if (*fileindex) {
6464 got_fileindex_free(*fileindex);
6465 *fileindex = NULL;
6467 lock_worktree(worktree, LOCK_SH);
6469 return err;
6472 const struct got_error *
6473 got_worktree_rebase_continue(struct got_object_id **commit_id,
6474 struct got_reference **new_base_branch, struct got_reference **tmp_branch,
6475 struct got_reference **branch, struct got_fileindex **fileindex,
6476 struct got_worktree *worktree, struct got_repository *repo)
6478 const struct got_error *err;
6479 char *commit_ref_name = NULL, *new_base_branch_ref_name = NULL;
6480 char *tmp_branch_name = NULL, *branch_ref_name = NULL;
6481 struct got_reference *commit_ref = NULL, *branch_ref = NULL;
6482 char *fileindex_path = NULL;
6483 int have_staged_files = 0;
6485 *commit_id = NULL;
6486 *new_base_branch = NULL;
6487 *tmp_branch = NULL;
6488 *branch = NULL;
6489 *fileindex = NULL;
6491 err = lock_worktree(worktree, LOCK_EX);
6492 if (err)
6493 return err;
6495 err = open_fileindex(fileindex, &fileindex_path, worktree);
6496 if (err)
6497 goto done;
6499 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
6500 &have_staged_files);
6501 if (err && err->code != GOT_ERR_CANCELLED)
6502 goto done;
6503 if (have_staged_files) {
6504 err = got_error(GOT_ERR_STAGED_PATHS);
6505 goto done;
6508 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
6509 if (err)
6510 goto done;
6512 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
6513 if (err)
6514 goto done;
6516 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
6517 if (err)
6518 goto done;
6520 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
6521 if (err)
6522 goto done;
6524 err = got_ref_open(&branch_ref, repo, branch_ref_name, 0);
6525 if (err)
6526 goto done;
6528 err = got_ref_open(branch, repo,
6529 got_ref_get_symref_target(branch_ref), 0);
6530 if (err)
6531 goto done;
6533 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6534 if (err)
6535 goto done;
6537 err = got_ref_resolve(commit_id, repo, commit_ref);
6538 if (err)
6539 goto done;
6541 err = got_ref_open(new_base_branch, repo,
6542 new_base_branch_ref_name, 0);
6543 if (err)
6544 goto done;
6546 err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0);
6547 if (err)
6548 goto done;
6549 done:
6550 free(commit_ref_name);
6551 free(branch_ref_name);
6552 free(fileindex_path);
6553 if (commit_ref)
6554 got_ref_close(commit_ref);
6555 if (branch_ref)
6556 got_ref_close(branch_ref);
6557 if (err) {
6558 free(*commit_id);
6559 *commit_id = NULL;
6560 if (*tmp_branch) {
6561 got_ref_close(*tmp_branch);
6562 *tmp_branch = NULL;
6564 if (*new_base_branch) {
6565 got_ref_close(*new_base_branch);
6566 *new_base_branch = NULL;
6568 if (*branch) {
6569 got_ref_close(*branch);
6570 *branch = NULL;
6572 if (*fileindex) {
6573 got_fileindex_free(*fileindex);
6574 *fileindex = NULL;
6576 lock_worktree(worktree, LOCK_SH);
6578 return err;
6581 const struct got_error *
6582 got_worktree_rebase_in_progress(int *in_progress, struct got_worktree *worktree)
6584 const struct got_error *err;
6585 char *tmp_branch_name = NULL;
6587 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
6588 if (err)
6589 return err;
6591 *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0);
6592 free(tmp_branch_name);
6593 return NULL;
6596 static const struct got_error *
6597 collect_rebase_commit_msg(struct got_pathlist_head *commitable_paths,
6598 const char *diff_path, char **logmsg, void *arg)
6600 *logmsg = arg;
6601 return NULL;
6604 static const struct got_error *
6605 rebase_status(void *arg, unsigned char status, unsigned char staged_status,
6606 const char *path, struct got_object_id *blob_id,
6607 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
6608 int dirfd, const char *de_name)
6610 return NULL;
6613 struct collect_merged_paths_arg {
6614 got_worktree_checkout_cb progress_cb;
6615 void *progress_arg;
6616 struct got_pathlist_head *merged_paths;
6619 static const struct got_error *
6620 collect_merged_paths(void *arg, unsigned char status, const char *path)
6622 const struct got_error *err;
6623 struct collect_merged_paths_arg *a = arg;
6624 char *p;
6625 struct got_pathlist_entry *new;
6627 err = (*a->progress_cb)(a->progress_arg, status, path);
6628 if (err)
6629 return err;
6631 if (status != GOT_STATUS_MERGE &&
6632 status != GOT_STATUS_ADD &&
6633 status != GOT_STATUS_DELETE &&
6634 status != GOT_STATUS_CONFLICT)
6635 return NULL;
6637 p = strdup(path);
6638 if (p == NULL)
6639 return got_error_from_errno("strdup");
6641 err = got_pathlist_insert(&new, a->merged_paths, p, NULL);
6642 if (err || new == NULL)
6643 free(p);
6644 return err;
6647 static const struct got_error *
6648 store_commit_id(const char *commit_ref_name, struct got_object_id *commit_id,
6649 int is_rebase, struct got_repository *repo)
6651 const struct got_error *err;
6652 struct got_reference *commit_ref = NULL;
6654 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6655 if (err) {
6656 if (err->code != GOT_ERR_NOT_REF)
6657 goto done;
6658 err = got_ref_alloc(&commit_ref, commit_ref_name, commit_id);
6659 if (err)
6660 goto done;
6661 err = got_ref_write(commit_ref, repo);
6662 if (err)
6663 goto done;
6664 } else if (is_rebase) {
6665 struct got_object_id *stored_id;
6666 int cmp;
6668 err = got_ref_resolve(&stored_id, repo, commit_ref);
6669 if (err)
6670 goto done;
6671 cmp = got_object_id_cmp(commit_id, stored_id);
6672 free(stored_id);
6673 if (cmp != 0) {
6674 err = got_error(GOT_ERR_REBASE_COMMITID);
6675 goto done;
6678 done:
6679 if (commit_ref)
6680 got_ref_close(commit_ref);
6681 return err;
6684 static const struct got_error *
6685 rebase_merge_files(struct got_pathlist_head *merged_paths,
6686 const char *commit_ref_name, struct got_worktree *worktree,
6687 struct got_fileindex *fileindex, struct got_object_id *parent_commit_id,
6688 struct got_object_id *commit_id, struct got_repository *repo,
6689 got_worktree_checkout_cb progress_cb, void *progress_arg,
6690 got_cancel_cb cancel_cb, void *cancel_arg)
6692 const struct got_error *err;
6693 struct got_reference *commit_ref = NULL;
6694 struct collect_merged_paths_arg cmp_arg;
6695 char *fileindex_path;
6697 /* Work tree is locked/unlocked during rebase preparation/teardown. */
6699 err = get_fileindex_path(&fileindex_path, worktree);
6700 if (err)
6701 return err;
6703 cmp_arg.progress_cb = progress_cb;
6704 cmp_arg.progress_arg = progress_arg;
6705 cmp_arg.merged_paths = merged_paths;
6706 err = merge_files(worktree, fileindex, fileindex_path,
6707 parent_commit_id, commit_id, repo, collect_merged_paths,
6708 &cmp_arg, cancel_cb, cancel_arg);
6709 if (commit_ref)
6710 got_ref_close(commit_ref);
6711 return err;
6714 const struct got_error *
6715 got_worktree_rebase_merge_files(struct got_pathlist_head *merged_paths,
6716 struct got_worktree *worktree, struct got_fileindex *fileindex,
6717 struct got_object_id *parent_commit_id, struct got_object_id *commit_id,
6718 struct got_repository *repo,
6719 got_worktree_checkout_cb progress_cb, void *progress_arg,
6720 got_cancel_cb cancel_cb, void *cancel_arg)
6722 const struct got_error *err;
6723 char *commit_ref_name;
6725 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
6726 if (err)
6727 return err;
6729 err = store_commit_id(commit_ref_name, commit_id, 1, repo);
6730 if (err)
6731 goto done;
6733 err = rebase_merge_files(merged_paths, commit_ref_name, worktree,
6734 fileindex, parent_commit_id, commit_id, repo, progress_cb,
6735 progress_arg, cancel_cb, cancel_arg);
6736 done:
6737 free(commit_ref_name);
6738 return err;
6741 const struct got_error *
6742 got_worktree_histedit_merge_files(struct got_pathlist_head *merged_paths,
6743 struct got_worktree *worktree, struct got_fileindex *fileindex,
6744 struct got_object_id *parent_commit_id, struct got_object_id *commit_id,
6745 struct got_repository *repo,
6746 got_worktree_checkout_cb progress_cb, void *progress_arg,
6747 got_cancel_cb cancel_cb, void *cancel_arg)
6749 const struct got_error *err;
6750 char *commit_ref_name;
6752 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
6753 if (err)
6754 return err;
6756 err = store_commit_id(commit_ref_name, commit_id, 0, repo);
6757 if (err)
6758 goto done;
6760 err = rebase_merge_files(merged_paths, commit_ref_name, worktree,
6761 fileindex, parent_commit_id, commit_id, repo, progress_cb,
6762 progress_arg, cancel_cb, cancel_arg);
6763 done:
6764 free(commit_ref_name);
6765 return err;
6768 static const struct got_error *
6769 rebase_commit(struct got_object_id **new_commit_id,
6770 struct got_pathlist_head *merged_paths, struct got_reference *commit_ref,
6771 struct got_worktree *worktree, struct got_fileindex *fileindex,
6772 struct got_reference *tmp_branch, const char *committer,
6773 struct got_commit_object *orig_commit, const char *new_logmsg,
6774 int allow_conflict, struct got_repository *repo)
6776 const struct got_error *err, *sync_err;
6777 struct got_pathlist_head commitable_paths;
6778 struct collect_commitables_arg cc_arg;
6779 char *fileindex_path = NULL;
6780 struct got_reference *head_ref = NULL;
6781 struct got_object_id *head_commit_id = NULL;
6782 char *logmsg = NULL;
6784 memset(&cc_arg, 0, sizeof(cc_arg));
6785 TAILQ_INIT(&commitable_paths);
6786 *new_commit_id = NULL;
6788 /* Work tree is locked/unlocked during rebase preparation/teardown. */
6790 err = get_fileindex_path(&fileindex_path, worktree);
6791 if (err)
6792 return err;
6794 cc_arg.commitable_paths = &commitable_paths;
6795 cc_arg.worktree = worktree;
6796 cc_arg.repo = repo;
6797 cc_arg.have_staged_files = 0;
6798 cc_arg.commit_conflicts = allow_conflict;
6800 * If possible get the status of individual files directly to
6801 * avoid crawling the entire work tree once per rebased commit.
6803 * Ideally, merged_paths would contain a list of commitables
6804 * we could use so we could skip worktree_status() entirely.
6805 * However, we would then need carefully keep track of cumulative
6806 * effects of operations such as file additions and deletions
6807 * in 'got histedit -f' (folding multiple commits into one),
6808 * and this extra complexity is not really worth it.
6810 if (merged_paths) {
6811 struct got_pathlist_entry *pe;
6812 TAILQ_FOREACH(pe, merged_paths, entry) {
6813 err = worktree_status(worktree, pe->path, fileindex,
6814 repo, collect_commitables, &cc_arg, NULL, NULL, 1,
6815 0);
6816 if (err)
6817 goto done;
6819 } else {
6820 err = worktree_status(worktree, "", fileindex, repo,
6821 collect_commitables, &cc_arg, NULL, NULL, 1, 0);
6822 if (err)
6823 goto done;
6826 if (TAILQ_EMPTY(&commitable_paths)) {
6827 /* No-op change; commit will be elided. */
6828 err = got_ref_delete(commit_ref, repo);
6829 if (err)
6830 goto done;
6831 err = got_error(GOT_ERR_COMMIT_NO_CHANGES);
6832 goto done;
6835 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
6836 if (err)
6837 goto done;
6839 err = got_ref_resolve(&head_commit_id, repo, head_ref);
6840 if (err)
6841 goto done;
6843 if (new_logmsg) {
6844 logmsg = strdup(new_logmsg);
6845 if (logmsg == NULL) {
6846 err = got_error_from_errno("strdup");
6847 goto done;
6849 } else {
6850 err = got_object_commit_get_logmsg(&logmsg, orig_commit);
6851 if (err)
6852 goto done;
6855 /* NB: commit_worktree will call free(logmsg) */
6856 err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id,
6857 NULL, worktree, got_object_commit_get_author(orig_commit),
6858 committer ? committer :
6859 got_object_commit_get_committer(orig_commit), NULL,
6860 collect_rebase_commit_msg, logmsg, rebase_status, NULL, repo);
6861 if (err)
6862 goto done;
6864 err = got_ref_change_ref(tmp_branch, *new_commit_id);
6865 if (err)
6866 goto done;
6868 err = got_ref_delete(commit_ref, repo);
6869 if (err)
6870 goto done;
6872 err = update_fileindex_after_commit(worktree, &commitable_paths,
6873 *new_commit_id, fileindex, 0);
6874 sync_err = sync_fileindex(fileindex, fileindex_path);
6875 if (sync_err && err == NULL)
6876 err = sync_err;
6877 done:
6878 free(fileindex_path);
6879 free(head_commit_id);
6880 if (head_ref)
6881 got_ref_close(head_ref);
6882 if (err) {
6883 free(*new_commit_id);
6884 *new_commit_id = NULL;
6886 return err;
6889 const struct got_error *
6890 got_worktree_rebase_commit(struct got_object_id **new_commit_id,
6891 struct got_pathlist_head *merged_paths, struct got_worktree *worktree,
6892 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
6893 const char *committer, struct got_commit_object *orig_commit,
6894 struct got_object_id *orig_commit_id, int allow_conflict,
6895 struct got_repository *repo)
6897 const struct got_error *err;
6898 char *commit_ref_name;
6899 struct got_reference *commit_ref = NULL;
6900 struct got_object_id *commit_id = NULL;
6902 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
6903 if (err)
6904 return err;
6906 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6907 if (err)
6908 goto done;
6909 err = got_ref_resolve(&commit_id, repo, commit_ref);
6910 if (err)
6911 goto done;
6912 if (got_object_id_cmp(commit_id, orig_commit_id) != 0) {
6913 err = got_error(GOT_ERR_REBASE_COMMITID);
6914 goto done;
6917 err = rebase_commit(new_commit_id, merged_paths, commit_ref,
6918 worktree, fileindex, tmp_branch, committer, orig_commit,
6919 NULL, allow_conflict, repo);
6920 done:
6921 if (commit_ref)
6922 got_ref_close(commit_ref);
6923 free(commit_ref_name);
6924 free(commit_id);
6925 return err;
6928 const struct got_error *
6929 got_worktree_histedit_commit(struct got_object_id **new_commit_id,
6930 struct got_pathlist_head *merged_paths, struct got_worktree *worktree,
6931 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
6932 const char *committer, struct got_commit_object *orig_commit,
6933 struct got_object_id *orig_commit_id, const char *new_logmsg,
6934 int allow_conflict, struct got_repository *repo)
6936 const struct got_error *err;
6937 char *commit_ref_name;
6938 struct got_reference *commit_ref = NULL;
6940 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
6941 if (err)
6942 return err;
6944 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6945 if (err)
6946 goto done;
6948 err = rebase_commit(new_commit_id, merged_paths, commit_ref,
6949 worktree, fileindex, tmp_branch, committer, orig_commit,
6950 new_logmsg, allow_conflict, repo);
6951 done:
6952 if (commit_ref)
6953 got_ref_close(commit_ref);
6954 free(commit_ref_name);
6955 return err;
6958 const struct got_error *
6959 got_worktree_rebase_postpone(struct got_worktree *worktree,
6960 struct got_fileindex *fileindex)
6962 if (fileindex)
6963 got_fileindex_free(fileindex);
6964 return lock_worktree(worktree, LOCK_SH);
6967 static const struct got_error *
6968 delete_ref(const char *name, struct got_repository *repo)
6970 const struct got_error *err;
6971 struct got_reference *ref;
6973 err = got_ref_open(&ref, repo, name, 0);
6974 if (err) {
6975 if (err->code == GOT_ERR_NOT_REF)
6976 return NULL;
6977 return err;
6980 err = got_ref_delete(ref, repo);
6981 got_ref_close(ref);
6982 return err;
6985 static const struct got_error *
6986 delete_rebase_refs(struct got_worktree *worktree, struct got_repository *repo)
6988 const struct got_error *err;
6989 char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL;
6990 char *branch_ref_name = NULL, *commit_ref_name = NULL;
6992 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
6993 if (err)
6994 goto done;
6995 err = delete_ref(tmp_branch_name, repo);
6996 if (err)
6997 goto done;
6999 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
7000 if (err)
7001 goto done;
7002 err = delete_ref(new_base_branch_ref_name, repo);
7003 if (err)
7004 goto done;
7006 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
7007 if (err)
7008 goto done;
7009 err = delete_ref(branch_ref_name, repo);
7010 if (err)
7011 goto done;
7013 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
7014 if (err)
7015 goto done;
7016 err = delete_ref(commit_ref_name, repo);
7017 if (err)
7018 goto done;
7020 done:
7021 free(tmp_branch_name);
7022 free(new_base_branch_ref_name);
7023 free(branch_ref_name);
7024 free(commit_ref_name);
7025 return err;
7028 static const struct got_error *
7029 create_backup_ref(const char *backup_ref_prefix, struct got_reference *branch,
7030 struct got_object_id *new_commit_id, struct got_repository *repo)
7032 const struct got_error *err;
7033 struct got_reference *ref = NULL;
7034 struct got_object_id *old_commit_id = NULL;
7035 const char *branch_name = NULL;
7036 char *new_id_str = NULL;
7037 char *refname = NULL;
7039 branch_name = got_ref_get_name(branch);
7040 if (strncmp(branch_name, "refs/heads/", 11) != 0)
7041 return got_error(GOT_ERR_BAD_REF_NAME); /* should not happen */
7042 branch_name += 11;
7044 err = got_object_id_str(&new_id_str, new_commit_id);
7045 if (err)
7046 return err;
7048 if (asprintf(&refname, "%s/%s/%s", backup_ref_prefix, branch_name,
7049 new_id_str) == -1) {
7050 err = got_error_from_errno("asprintf");
7051 goto done;
7054 err = got_ref_resolve(&old_commit_id, repo, branch);
7055 if (err)
7056 goto done;
7058 err = got_ref_alloc(&ref, refname, old_commit_id);
7059 if (err)
7060 goto done;
7062 err = got_ref_write(ref, repo);
7063 done:
7064 free(new_id_str);
7065 free(refname);
7066 free(old_commit_id);
7067 if (ref)
7068 got_ref_close(ref);
7069 return err;
7072 const struct got_error *
7073 got_worktree_rebase_complete(struct got_worktree *worktree,
7074 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
7075 struct got_reference *rebased_branch, struct got_repository *repo,
7076 int create_backup)
7078 const struct got_error *err, *unlockerr, *sync_err;
7079 struct got_object_id *new_head_commit_id = NULL;
7080 char *fileindex_path = NULL;
7082 err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch);
7083 if (err)
7084 return err;
7086 if (create_backup) {
7087 err = create_backup_ref(GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX,
7088 rebased_branch, new_head_commit_id, repo);
7089 if (err)
7090 goto done;
7093 err = got_ref_change_ref(rebased_branch, new_head_commit_id);
7094 if (err)
7095 goto done;
7097 err = got_ref_write(rebased_branch, repo);
7098 if (err)
7099 goto done;
7101 err = got_worktree_set_head_ref(worktree, rebased_branch);
7102 if (err)
7103 goto done;
7105 err = delete_rebase_refs(worktree, repo);
7106 if (err)
7107 goto done;
7109 err = get_fileindex_path(&fileindex_path, worktree);
7110 if (err)
7111 goto done;
7112 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
7113 sync_err = sync_fileindex(fileindex, fileindex_path);
7114 if (sync_err && err == NULL)
7115 err = sync_err;
7116 done:
7117 got_fileindex_free(fileindex);
7118 free(fileindex_path);
7119 free(new_head_commit_id);
7120 unlockerr = lock_worktree(worktree, LOCK_SH);
7121 if (unlockerr && err == NULL)
7122 err = unlockerr;
7123 return err;
7126 const struct got_error *
7127 got_worktree_rebase_abort(struct got_worktree *worktree,
7128 struct got_fileindex *fileindex, struct got_repository *repo,
7129 struct got_reference *new_base_branch,
7130 got_worktree_checkout_cb progress_cb, void *progress_arg)
7132 const struct got_error *err, *unlockerr, *sync_err;
7133 struct got_reference *resolved = NULL;
7134 struct got_object_id *commit_id = NULL;
7135 struct got_commit_object *commit = NULL;
7136 char *fileindex_path = NULL;
7137 struct revert_file_args rfa;
7138 struct got_object_id *tree_id = NULL;
7140 err = lock_worktree(worktree, LOCK_EX);
7141 if (err)
7142 return err;
7144 err = got_object_open_as_commit(&commit, repo,
7145 worktree->base_commit_id);
7146 if (err)
7147 goto done;
7149 err = got_ref_open(&resolved, repo,
7150 got_ref_get_symref_target(new_base_branch), 0);
7151 if (err)
7152 goto done;
7154 err = got_worktree_set_head_ref(worktree, resolved);
7155 if (err)
7156 goto done;
7159 * XXX commits to the base branch could have happened while
7160 * we were busy rebasing; should we store the original commit ID
7161 * when rebase begins and read it back here?
7163 err = got_ref_resolve(&commit_id, repo, resolved);
7164 if (err)
7165 goto done;
7167 err = got_worktree_set_base_commit_id(worktree, repo, commit_id);
7168 if (err)
7169 goto done;
7171 err = got_object_id_by_path(&tree_id, repo, commit,
7172 worktree->path_prefix);
7173 if (err)
7174 goto done;
7176 err = delete_rebase_refs(worktree, repo);
7177 if (err)
7178 goto done;
7180 err = get_fileindex_path(&fileindex_path, worktree);
7181 if (err)
7182 goto done;
7184 rfa.worktree = worktree;
7185 rfa.fileindex = fileindex;
7186 rfa.progress_cb = progress_cb;
7187 rfa.progress_arg = progress_arg;
7188 rfa.patch_cb = NULL;
7189 rfa.patch_arg = NULL;
7190 rfa.repo = repo;
7191 rfa.unlink_added_files = 0;
7192 err = worktree_status(worktree, "", fileindex, repo,
7193 revert_file, &rfa, NULL, NULL, 1, 0);
7194 if (err)
7195 goto sync;
7197 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
7198 repo, progress_cb, progress_arg, NULL, NULL);
7199 sync:
7200 sync_err = sync_fileindex(fileindex, fileindex_path);
7201 if (sync_err && err == NULL)
7202 err = sync_err;
7203 done:
7204 got_ref_close(resolved);
7205 free(tree_id);
7206 free(commit_id);
7207 if (commit)
7208 got_object_commit_close(commit);
7209 if (fileindex)
7210 got_fileindex_free(fileindex);
7211 free(fileindex_path);
7213 unlockerr = lock_worktree(worktree, LOCK_SH);
7214 if (unlockerr && err == NULL)
7215 err = unlockerr;
7216 return err;
7219 const struct got_error *
7220 got_worktree_histedit_prepare(struct got_reference **tmp_branch,
7221 struct got_reference **branch_ref, struct got_object_id **base_commit_id,
7222 struct got_fileindex **fileindex, struct got_worktree *worktree,
7223 struct got_repository *repo)
7225 const struct got_error *err = NULL;
7226 char *tmp_branch_name = NULL;
7227 char *branch_ref_name = NULL;
7228 char *base_commit_ref_name = NULL;
7229 char *fileindex_path = NULL;
7230 struct check_rebase_ok_arg ok_arg;
7231 struct got_reference *wt_branch = NULL;
7232 struct got_reference *base_commit_ref = NULL;
7234 *tmp_branch = NULL;
7235 *branch_ref = NULL;
7236 *base_commit_id = NULL;
7237 *fileindex = NULL;
7239 err = lock_worktree(worktree, LOCK_EX);
7240 if (err)
7241 return err;
7243 err = open_fileindex(fileindex, &fileindex_path, worktree);
7244 if (err)
7245 goto done;
7247 ok_arg.worktree = worktree;
7248 ok_arg.repo = repo;
7249 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
7250 &ok_arg);
7251 if (err)
7252 goto done;
7254 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
7255 if (err)
7256 goto done;
7258 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
7259 if (err)
7260 goto done;
7262 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
7263 worktree);
7264 if (err)
7265 goto done;
7267 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
7268 0);
7269 if (err)
7270 goto done;
7272 err = got_ref_alloc_symref(branch_ref, branch_ref_name, wt_branch);
7273 if (err)
7274 goto done;
7276 err = got_ref_write(*branch_ref, repo);
7277 if (err)
7278 goto done;
7280 err = got_ref_alloc(&base_commit_ref, base_commit_ref_name,
7281 worktree->base_commit_id);
7282 if (err)
7283 goto done;
7284 err = got_ref_write(base_commit_ref, repo);
7285 if (err)
7286 goto done;
7287 *base_commit_id = got_object_id_dup(worktree->base_commit_id);
7288 if (*base_commit_id == NULL) {
7289 err = got_error_from_errno("got_object_id_dup");
7290 goto done;
7293 err = got_ref_alloc(tmp_branch, tmp_branch_name,
7294 worktree->base_commit_id);
7295 if (err)
7296 goto done;
7297 err = got_ref_write(*tmp_branch, repo);
7298 if (err)
7299 goto done;
7301 err = got_worktree_set_head_ref(worktree, *tmp_branch);
7302 if (err)
7303 goto done;
7304 done:
7305 free(fileindex_path);
7306 free(tmp_branch_name);
7307 free(branch_ref_name);
7308 free(base_commit_ref_name);
7309 if (wt_branch)
7310 got_ref_close(wt_branch);
7311 if (err) {
7312 if (*branch_ref) {
7313 got_ref_close(*branch_ref);
7314 *branch_ref = NULL;
7316 if (*tmp_branch) {
7317 got_ref_close(*tmp_branch);
7318 *tmp_branch = NULL;
7320 free(*base_commit_id);
7321 if (*fileindex) {
7322 got_fileindex_free(*fileindex);
7323 *fileindex = NULL;
7325 lock_worktree(worktree, LOCK_SH);
7327 return err;
7330 const struct got_error *
7331 got_worktree_histedit_postpone(struct got_worktree *worktree,
7332 struct got_fileindex *fileindex)
7334 if (fileindex)
7335 got_fileindex_free(fileindex);
7336 return lock_worktree(worktree, LOCK_SH);
7339 const struct got_error *
7340 got_worktree_histedit_in_progress(int *in_progress,
7341 struct got_worktree *worktree)
7343 const struct got_error *err;
7344 char *tmp_branch_name = NULL;
7346 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
7347 if (err)
7348 return err;
7350 *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0);
7351 free(tmp_branch_name);
7352 return NULL;
7355 const struct got_error *
7356 got_worktree_histedit_continue(struct got_object_id **commit_id,
7357 struct got_reference **tmp_branch, struct got_reference **branch_ref,
7358 struct got_object_id **base_commit_id, struct got_fileindex **fileindex,
7359 struct got_worktree *worktree, struct got_repository *repo)
7361 const struct got_error *err;
7362 char *commit_ref_name = NULL, *base_commit_ref_name = NULL;
7363 char *tmp_branch_name = NULL, *branch_ref_name = NULL;
7364 struct got_reference *commit_ref = NULL;
7365 struct got_reference *base_commit_ref = NULL;
7366 char *fileindex_path = NULL;
7367 int have_staged_files = 0;
7369 *commit_id = NULL;
7370 *tmp_branch = NULL;
7371 *base_commit_id = NULL;
7372 *fileindex = NULL;
7374 err = lock_worktree(worktree, LOCK_EX);
7375 if (err)
7376 return err;
7378 err = open_fileindex(fileindex, &fileindex_path, worktree);
7379 if (err)
7380 goto done;
7382 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
7383 &have_staged_files);
7384 if (err && err->code != GOT_ERR_CANCELLED)
7385 goto done;
7386 if (have_staged_files) {
7387 err = got_error(GOT_ERR_STAGED_PATHS);
7388 goto done;
7391 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
7392 if (err)
7393 goto done;
7395 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
7396 if (err)
7397 goto done;
7399 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
7400 if (err)
7401 goto done;
7403 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
7404 worktree);
7405 if (err)
7406 goto done;
7408 err = got_ref_open(branch_ref, repo, branch_ref_name, 0);
7409 if (err)
7410 goto done;
7412 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
7413 if (err)
7414 goto done;
7415 err = got_ref_resolve(commit_id, repo, commit_ref);
7416 if (err)
7417 goto done;
7419 err = got_ref_open(&base_commit_ref, repo, base_commit_ref_name, 0);
7420 if (err)
7421 goto done;
7422 err = got_ref_resolve(base_commit_id, repo, base_commit_ref);
7423 if (err)
7424 goto done;
7426 err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0);
7427 if (err)
7428 goto done;
7429 done:
7430 free(commit_ref_name);
7431 free(branch_ref_name);
7432 free(fileindex_path);
7433 if (commit_ref)
7434 got_ref_close(commit_ref);
7435 if (base_commit_ref)
7436 got_ref_close(base_commit_ref);
7437 if (err) {
7438 free(*commit_id);
7439 *commit_id = NULL;
7440 free(*base_commit_id);
7441 *base_commit_id = NULL;
7442 if (*tmp_branch) {
7443 got_ref_close(*tmp_branch);
7444 *tmp_branch = NULL;
7446 if (*fileindex) {
7447 got_fileindex_free(*fileindex);
7448 *fileindex = NULL;
7450 lock_worktree(worktree, LOCK_EX);
7452 return err;
7455 static const struct got_error *
7456 delete_histedit_refs(struct got_worktree *worktree, struct got_repository *repo)
7458 const struct got_error *err;
7459 char *tmp_branch_name = NULL, *base_commit_ref_name = NULL;
7460 char *branch_ref_name = NULL, *commit_ref_name = NULL;
7462 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
7463 if (err)
7464 goto done;
7465 err = delete_ref(tmp_branch_name, repo);
7466 if (err)
7467 goto done;
7469 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
7470 worktree);
7471 if (err)
7472 goto done;
7473 err = delete_ref(base_commit_ref_name, repo);
7474 if (err)
7475 goto done;
7477 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
7478 if (err)
7479 goto done;
7480 err = delete_ref(branch_ref_name, repo);
7481 if (err)
7482 goto done;
7484 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
7485 if (err)
7486 goto done;
7487 err = delete_ref(commit_ref_name, repo);
7488 if (err)
7489 goto done;
7490 done:
7491 free(tmp_branch_name);
7492 free(base_commit_ref_name);
7493 free(branch_ref_name);
7494 free(commit_ref_name);
7495 return err;
7498 const struct got_error *
7499 got_worktree_histedit_abort(struct got_worktree *worktree,
7500 struct got_fileindex *fileindex, struct got_repository *repo,
7501 struct got_reference *branch, struct got_object_id *base_commit_id,
7502 got_worktree_checkout_cb progress_cb, void *progress_arg)
7504 const struct got_error *err, *unlockerr, *sync_err;
7505 struct got_reference *resolved = NULL;
7506 char *fileindex_path = NULL;
7507 struct got_commit_object *commit = NULL;
7508 struct got_object_id *tree_id = NULL;
7509 struct revert_file_args rfa;
7511 err = lock_worktree(worktree, LOCK_EX);
7512 if (err)
7513 return err;
7515 err = got_object_open_as_commit(&commit, repo,
7516 worktree->base_commit_id);
7517 if (err)
7518 goto done;
7520 err = got_ref_open(&resolved, repo,
7521 got_ref_get_symref_target(branch), 0);
7522 if (err)
7523 goto done;
7525 err = got_worktree_set_head_ref(worktree, resolved);
7526 if (err)
7527 goto done;
7529 err = got_worktree_set_base_commit_id(worktree, repo, base_commit_id);
7530 if (err)
7531 goto done;
7533 err = got_object_id_by_path(&tree_id, repo, commit,
7534 worktree->path_prefix);
7535 if (err)
7536 goto done;
7538 err = delete_histedit_refs(worktree, repo);
7539 if (err)
7540 goto done;
7542 err = get_fileindex_path(&fileindex_path, worktree);
7543 if (err)
7544 goto done;
7546 rfa.worktree = worktree;
7547 rfa.fileindex = fileindex;
7548 rfa.progress_cb = progress_cb;
7549 rfa.progress_arg = progress_arg;
7550 rfa.patch_cb = NULL;
7551 rfa.patch_arg = NULL;
7552 rfa.repo = repo;
7553 rfa.unlink_added_files = 0;
7554 err = worktree_status(worktree, "", fileindex, repo,
7555 revert_file, &rfa, NULL, NULL, 1, 0);
7556 if (err)
7557 goto sync;
7559 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
7560 repo, progress_cb, progress_arg, NULL, NULL);
7561 sync:
7562 sync_err = sync_fileindex(fileindex, fileindex_path);
7563 if (sync_err && err == NULL)
7564 err = sync_err;
7565 done:
7566 got_ref_close(resolved);
7567 free(tree_id);
7568 free(fileindex_path);
7570 unlockerr = lock_worktree(worktree, LOCK_SH);
7571 if (unlockerr && err == NULL)
7572 err = unlockerr;
7573 return err;
7576 const struct got_error *
7577 got_worktree_histedit_complete(struct got_worktree *worktree,
7578 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
7579 struct got_reference *edited_branch, struct got_repository *repo)
7581 const struct got_error *err, *unlockerr, *sync_err;
7582 struct got_object_id *new_head_commit_id = NULL;
7583 struct got_reference *resolved = NULL;
7584 char *fileindex_path = NULL;
7586 err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch);
7587 if (err)
7588 return err;
7590 err = got_ref_open(&resolved, repo,
7591 got_ref_get_symref_target(edited_branch), 0);
7592 if (err)
7593 goto done;
7595 err = create_backup_ref(GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX,
7596 resolved, new_head_commit_id, repo);
7597 if (err)
7598 goto done;
7600 err = got_ref_change_ref(resolved, new_head_commit_id);
7601 if (err)
7602 goto done;
7604 err = got_ref_write(resolved, repo);
7605 if (err)
7606 goto done;
7608 err = got_worktree_set_head_ref(worktree, resolved);
7609 if (err)
7610 goto done;
7612 err = delete_histedit_refs(worktree, repo);
7613 if (err)
7614 goto done;
7616 err = get_fileindex_path(&fileindex_path, worktree);
7617 if (err)
7618 goto done;
7619 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
7620 sync_err = sync_fileindex(fileindex, fileindex_path);
7621 if (sync_err && err == NULL)
7622 err = sync_err;
7623 done:
7624 got_fileindex_free(fileindex);
7625 free(fileindex_path);
7626 free(new_head_commit_id);
7627 unlockerr = lock_worktree(worktree, LOCK_SH);
7628 if (unlockerr && err == NULL)
7629 err = unlockerr;
7630 return err;
7633 const struct got_error *
7634 got_worktree_histedit_skip_commit(struct got_worktree *worktree,
7635 struct got_object_id *commit_id, struct got_repository *repo)
7637 const struct got_error *err;
7638 char *commit_ref_name;
7640 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
7641 if (err)
7642 return err;
7644 err = store_commit_id(commit_ref_name, commit_id, 0, repo);
7645 if (err)
7646 goto done;
7648 err = delete_ref(commit_ref_name, repo);
7649 done:
7650 free(commit_ref_name);
7651 return err;
7654 const struct got_error *
7655 got_worktree_integrate_prepare(struct got_fileindex **fileindex,
7656 struct got_reference **branch_ref, struct got_reference **base_branch_ref,
7657 struct got_worktree *worktree, const char *refname,
7658 struct got_repository *repo)
7660 const struct got_error *err = NULL;
7661 char *fileindex_path = NULL;
7662 struct check_rebase_ok_arg ok_arg;
7664 *fileindex = NULL;
7665 *branch_ref = NULL;
7666 *base_branch_ref = NULL;
7668 err = lock_worktree(worktree, LOCK_EX);
7669 if (err)
7670 return err;
7672 if (strcmp(refname, got_worktree_get_head_ref_name(worktree)) == 0) {
7673 err = got_error_msg(GOT_ERR_SAME_BRANCH,
7674 "cannot integrate a branch into itself; "
7675 "update -b or different branch name required");
7676 goto done;
7679 err = open_fileindex(fileindex, &fileindex_path, worktree);
7680 if (err)
7681 goto done;
7683 /* Preconditions are the same as for rebase. */
7684 ok_arg.worktree = worktree;
7685 ok_arg.repo = repo;
7686 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
7687 &ok_arg);
7688 if (err)
7689 goto done;
7691 err = got_ref_open(branch_ref, repo, refname, 1);
7692 if (err)
7693 goto done;
7695 err = got_ref_open(base_branch_ref, repo,
7696 got_worktree_get_head_ref_name(worktree), 1);
7697 done:
7698 if (err) {
7699 if (*branch_ref) {
7700 got_ref_close(*branch_ref);
7701 *branch_ref = NULL;
7703 if (*base_branch_ref) {
7704 got_ref_close(*base_branch_ref);
7705 *base_branch_ref = NULL;
7707 if (*fileindex) {
7708 got_fileindex_free(*fileindex);
7709 *fileindex = NULL;
7711 lock_worktree(worktree, LOCK_SH);
7713 return err;
7716 const struct got_error *
7717 got_worktree_integrate_continue(struct got_worktree *worktree,
7718 struct got_fileindex *fileindex, struct got_repository *repo,
7719 struct got_reference *branch_ref, struct got_reference *base_branch_ref,
7720 got_worktree_checkout_cb progress_cb, void *progress_arg,
7721 got_cancel_cb cancel_cb, void *cancel_arg)
7723 const struct got_error *err = NULL, *sync_err, *unlockerr;
7724 char *fileindex_path = NULL;
7725 struct got_object_id *tree_id = NULL, *commit_id = NULL;
7726 struct got_commit_object *commit = NULL;
7728 err = get_fileindex_path(&fileindex_path, worktree);
7729 if (err)
7730 goto done;
7732 err = got_ref_resolve(&commit_id, repo, branch_ref);
7733 if (err)
7734 goto done;
7736 err = got_object_open_as_commit(&commit, repo, commit_id);
7737 if (err)
7738 goto done;
7740 err = got_object_id_by_path(&tree_id, repo, commit,
7741 worktree->path_prefix);
7742 if (err)
7743 goto done;
7745 err = got_worktree_set_base_commit_id(worktree, repo, commit_id);
7746 if (err)
7747 goto done;
7749 err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo,
7750 progress_cb, progress_arg, cancel_cb, cancel_arg);
7751 if (err)
7752 goto sync;
7754 err = got_ref_change_ref(base_branch_ref, commit_id);
7755 if (err)
7756 goto sync;
7758 err = got_ref_write(base_branch_ref, repo);
7759 if (err)
7760 goto sync;
7762 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
7763 sync:
7764 sync_err = sync_fileindex(fileindex, fileindex_path);
7765 if (sync_err && err == NULL)
7766 err = sync_err;
7768 done:
7769 unlockerr = got_ref_unlock(branch_ref);
7770 if (unlockerr && err == NULL)
7771 err = unlockerr;
7772 got_ref_close(branch_ref);
7774 unlockerr = got_ref_unlock(base_branch_ref);
7775 if (unlockerr && err == NULL)
7776 err = unlockerr;
7777 got_ref_close(base_branch_ref);
7779 got_fileindex_free(fileindex);
7780 free(fileindex_path);
7781 free(tree_id);
7782 if (commit)
7783 got_object_commit_close(commit);
7785 unlockerr = lock_worktree(worktree, LOCK_SH);
7786 if (unlockerr && err == NULL)
7787 err = unlockerr;
7788 return err;
7791 const struct got_error *
7792 got_worktree_integrate_abort(struct got_worktree *worktree,
7793 struct got_fileindex *fileindex, struct got_repository *repo,
7794 struct got_reference *branch_ref, struct got_reference *base_branch_ref)
7796 const struct got_error *err = NULL, *unlockerr = NULL;
7798 got_fileindex_free(fileindex);
7800 err = lock_worktree(worktree, LOCK_SH);
7802 unlockerr = got_ref_unlock(branch_ref);
7803 if (unlockerr && err == NULL)
7804 err = unlockerr;
7805 got_ref_close(branch_ref);
7807 unlockerr = got_ref_unlock(base_branch_ref);
7808 if (unlockerr && err == NULL)
7809 err = unlockerr;
7810 got_ref_close(base_branch_ref);
7812 return err;
7815 const struct got_error *
7816 got_worktree_merge_postpone(struct got_worktree *worktree,
7817 struct got_fileindex *fileindex)
7819 const struct got_error *err, *sync_err;
7820 char *fileindex_path = NULL;
7822 err = get_fileindex_path(&fileindex_path, worktree);
7823 if (err)
7824 goto done;
7826 sync_err = sync_fileindex(fileindex, fileindex_path);
7828 err = lock_worktree(worktree, LOCK_SH);
7829 if (sync_err && err == NULL)
7830 err = sync_err;
7831 done:
7832 got_fileindex_free(fileindex);
7833 free(fileindex_path);
7834 return err;
7837 static const struct got_error *
7838 delete_merge_refs(struct got_worktree *worktree, struct got_repository *repo)
7840 const struct got_error *err;
7841 char *branch_refname = NULL, *commit_refname = NULL;
7843 err = get_merge_branch_ref_name(&branch_refname, worktree);
7844 if (err)
7845 goto done;
7846 err = delete_ref(branch_refname, repo);
7847 if (err)
7848 goto done;
7850 err = get_merge_commit_ref_name(&commit_refname, worktree);
7851 if (err)
7852 goto done;
7853 err = delete_ref(commit_refname, repo);
7854 if (err)
7855 goto done;
7857 done:
7858 free(branch_refname);
7859 free(commit_refname);
7860 return err;
7863 struct merge_commit_msg_arg {
7864 struct got_worktree *worktree;
7865 const char *branch_name;
7868 static const struct got_error *
7869 merge_commit_msg_cb(struct got_pathlist_head *commitable_paths,
7870 const char *diff_path, char **logmsg, void *arg)
7872 struct merge_commit_msg_arg *a = arg;
7874 if (asprintf(logmsg, "merge %s into %s\n", a->branch_name,
7875 got_worktree_get_head_ref_name(a->worktree)) == -1)
7876 return got_error_from_errno("asprintf");
7878 return NULL;
7882 const struct got_error *
7883 got_worktree_merge_branch(struct got_worktree *worktree,
7884 struct got_fileindex *fileindex,
7885 struct got_object_id *yca_commit_id,
7886 struct got_object_id *branch_tip,
7887 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
7888 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
7890 const struct got_error *err;
7891 char *fileindex_path = NULL;
7893 err = get_fileindex_path(&fileindex_path, worktree);
7894 if (err)
7895 goto done;
7897 err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits,
7898 worktree);
7899 if (err)
7900 goto done;
7902 err = merge_files(worktree, fileindex, fileindex_path, yca_commit_id,
7903 branch_tip, repo, progress_cb, progress_arg,
7904 cancel_cb, cancel_arg);
7905 done:
7906 free(fileindex_path);
7907 return err;
7910 const struct got_error *
7911 got_worktree_merge_commit(struct got_object_id **new_commit_id,
7912 struct got_worktree *worktree, struct got_fileindex *fileindex,
7913 const char *author, const char *committer, int allow_bad_symlinks,
7914 struct got_object_id *branch_tip, const char *branch_name,
7915 int allow_conflict, struct got_repository *repo,
7916 got_worktree_status_cb status_cb, void *status_arg)
7919 const struct got_error *err = NULL, *sync_err;
7920 struct got_pathlist_head commitable_paths;
7921 struct collect_commitables_arg cc_arg;
7922 struct got_pathlist_entry *pe;
7923 struct got_reference *head_ref = NULL;
7924 struct got_object_id *head_commit_id = NULL;
7925 int have_staged_files = 0;
7926 struct merge_commit_msg_arg mcm_arg;
7927 char *fileindex_path = NULL;
7929 memset(&cc_arg, 0, sizeof(cc_arg));
7930 *new_commit_id = NULL;
7932 TAILQ_INIT(&commitable_paths);
7934 err = get_fileindex_path(&fileindex_path, worktree);
7935 if (err)
7936 goto done;
7938 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
7939 if (err)
7940 goto done;
7942 err = got_ref_resolve(&head_commit_id, repo, head_ref);
7943 if (err)
7944 goto done;
7946 err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file,
7947 &have_staged_files);
7948 if (err && err->code != GOT_ERR_CANCELLED)
7949 goto done;
7950 if (have_staged_files) {
7951 err = got_error(GOT_ERR_MERGE_STAGED_PATHS);
7952 goto done;
7955 cc_arg.commitable_paths = &commitable_paths;
7956 cc_arg.worktree = worktree;
7957 cc_arg.fileindex = fileindex;
7958 cc_arg.repo = repo;
7959 cc_arg.have_staged_files = have_staged_files;
7960 cc_arg.allow_bad_symlinks = allow_bad_symlinks;
7961 cc_arg.commit_conflicts = allow_conflict;
7962 err = worktree_status(worktree, "", fileindex, repo,
7963 collect_commitables, &cc_arg, NULL, NULL, 1, 0);
7964 if (err)
7965 goto done;
7967 if (TAILQ_EMPTY(&commitable_paths)) {
7968 err = got_error_fmt(GOT_ERR_COMMIT_NO_CHANGES,
7969 "merge of %s cannot proceed", branch_name);
7970 goto done;
7973 TAILQ_FOREACH(pe, &commitable_paths, entry) {
7974 struct got_commitable *ct = pe->data;
7975 const char *ct_path = ct->in_repo_path;
7977 while (ct_path[0] == '/')
7978 ct_path++;
7979 err = check_out_of_date(ct_path, ct->status,
7980 ct->staged_status, ct->base_blob_id, ct->base_commit_id,
7981 head_commit_id, repo, GOT_ERR_MERGE_COMMIT_OUT_OF_DATE);
7982 if (err)
7983 goto done;
7987 mcm_arg.worktree = worktree;
7988 mcm_arg.branch_name = branch_name;
7989 err = commit_worktree(new_commit_id, &commitable_paths,
7990 head_commit_id, branch_tip, worktree, author, committer, NULL,
7991 merge_commit_msg_cb, &mcm_arg, status_cb, status_arg, repo);
7992 if (err)
7993 goto done;
7995 err = update_fileindex_after_commit(worktree, &commitable_paths,
7996 *new_commit_id, fileindex, have_staged_files);
7997 sync_err = sync_fileindex(fileindex, fileindex_path);
7998 if (sync_err && err == NULL)
7999 err = sync_err;
8000 done:
8001 TAILQ_FOREACH(pe, &commitable_paths, entry) {
8002 struct got_commitable *ct = pe->data;
8004 free_commitable(ct);
8006 got_pathlist_free(&commitable_paths, GOT_PATHLIST_FREE_NONE);
8007 free(fileindex_path);
8008 return err;
8011 const struct got_error *
8012 got_worktree_merge_complete(struct got_worktree *worktree,
8013 struct got_fileindex *fileindex, struct got_repository *repo)
8015 const struct got_error *err, *unlockerr, *sync_err;
8016 char *fileindex_path = NULL;
8018 err = delete_merge_refs(worktree, repo);
8019 if (err)
8020 goto done;
8022 err = get_fileindex_path(&fileindex_path, worktree);
8023 if (err)
8024 goto done;
8025 err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL);
8026 sync_err = sync_fileindex(fileindex, fileindex_path);
8027 if (sync_err && err == NULL)
8028 err = sync_err;
8029 done:
8030 got_fileindex_free(fileindex);
8031 free(fileindex_path);
8032 unlockerr = lock_worktree(worktree, LOCK_SH);
8033 if (unlockerr && err == NULL)
8034 err = unlockerr;
8035 return err;
8038 const struct got_error *
8039 got_worktree_merge_in_progress(int *in_progress, struct got_worktree *worktree,
8040 struct got_repository *repo)
8042 const struct got_error *err;
8043 char *branch_refname = NULL;
8044 struct got_reference *branch_ref = NULL;
8046 *in_progress = 0;
8048 err = get_merge_branch_ref_name(&branch_refname, worktree);
8049 if (err)
8050 return err;
8051 err = got_ref_open(&branch_ref, repo, branch_refname, 0);
8052 free(branch_refname);
8053 if (err) {
8054 if (err->code != GOT_ERR_NOT_REF)
8055 return err;
8056 } else
8057 *in_progress = 1;
8059 return NULL;
8062 const struct got_error *got_worktree_merge_prepare(
8063 struct got_fileindex **fileindex, struct got_worktree *worktree,
8064 struct got_reference *branch, struct got_repository *repo)
8066 const struct got_error *err = NULL;
8067 char *fileindex_path = NULL;
8068 char *branch_refname = NULL, *commit_refname = NULL;
8069 struct got_reference *wt_branch = NULL, *branch_ref = NULL;
8070 struct got_reference *commit_ref = NULL;
8071 struct got_object_id *branch_tip = NULL, *wt_branch_tip = NULL;
8072 struct check_rebase_ok_arg ok_arg;
8074 *fileindex = NULL;
8076 err = lock_worktree(worktree, LOCK_EX);
8077 if (err)
8078 return err;
8080 err = open_fileindex(fileindex, &fileindex_path, worktree);
8081 if (err)
8082 goto done;
8084 /* Preconditions are the same as for rebase. */
8085 ok_arg.worktree = worktree;
8086 ok_arg.repo = repo;
8087 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
8088 &ok_arg);
8089 if (err)
8090 goto done;
8092 err = get_merge_branch_ref_name(&branch_refname, worktree);
8093 if (err)
8094 return err;
8096 err = get_merge_commit_ref_name(&commit_refname, worktree);
8097 if (err)
8098 return err;
8100 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
8101 0);
8102 if (err)
8103 goto done;
8105 err = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
8106 if (err)
8107 goto done;
8109 if (got_object_id_cmp(worktree->base_commit_id, wt_branch_tip) != 0) {
8110 err = got_error(GOT_ERR_MERGE_OUT_OF_DATE);
8111 goto done;
8114 err = got_ref_resolve(&branch_tip, repo, branch);
8115 if (err)
8116 goto done;
8118 err = got_ref_alloc_symref(&branch_ref, branch_refname, branch);
8119 if (err)
8120 goto done;
8121 err = got_ref_write(branch_ref, repo);
8122 if (err)
8123 goto done;
8125 err = got_ref_alloc(&commit_ref, commit_refname, branch_tip);
8126 if (err)
8127 goto done;
8128 err = got_ref_write(commit_ref, repo);
8129 if (err)
8130 goto done;
8132 done:
8133 free(branch_refname);
8134 free(commit_refname);
8135 free(fileindex_path);
8136 if (branch_ref)
8137 got_ref_close(branch_ref);
8138 if (commit_ref)
8139 got_ref_close(commit_ref);
8140 if (wt_branch)
8141 got_ref_close(wt_branch);
8142 free(wt_branch_tip);
8143 if (err) {
8144 if (*fileindex) {
8145 got_fileindex_free(*fileindex);
8146 *fileindex = NULL;
8148 lock_worktree(worktree, LOCK_SH);
8150 return err;
8153 const struct got_error *
8154 got_worktree_merge_continue(char **branch_name,
8155 struct got_object_id **branch_tip, struct got_fileindex **fileindex,
8156 struct got_worktree *worktree, struct got_repository *repo)
8158 const struct got_error *err;
8159 char *commit_refname = NULL, *branch_refname = NULL;
8160 struct got_reference *commit_ref = NULL, *branch_ref = NULL;
8161 char *fileindex_path = NULL;
8162 int have_staged_files = 0;
8164 *branch_name = NULL;
8165 *branch_tip = NULL;
8166 *fileindex = NULL;
8168 err = lock_worktree(worktree, LOCK_EX);
8169 if (err)
8170 return err;
8172 err = open_fileindex(fileindex, &fileindex_path, worktree);
8173 if (err)
8174 goto done;
8176 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
8177 &have_staged_files);
8178 if (err && err->code != GOT_ERR_CANCELLED)
8179 goto done;
8180 if (have_staged_files) {
8181 err = got_error(GOT_ERR_STAGED_PATHS);
8182 goto done;
8185 err = get_merge_branch_ref_name(&branch_refname, worktree);
8186 if (err)
8187 goto done;
8189 err = get_merge_commit_ref_name(&commit_refname, worktree);
8190 if (err)
8191 goto done;
8193 err = got_ref_open(&branch_ref, repo, branch_refname, 0);
8194 if (err)
8195 goto done;
8197 if (!got_ref_is_symbolic(branch_ref)) {
8198 err = got_error_fmt(GOT_ERR_BAD_REF_TYPE,
8199 "%s is not a symbolic reference",
8200 got_ref_get_name(branch_ref));
8201 goto done;
8203 *branch_name = strdup(got_ref_get_symref_target(branch_ref));
8204 if (*branch_name == NULL) {
8205 err = got_error_from_errno("strdup");
8206 goto done;
8209 err = got_ref_open(&commit_ref, repo, commit_refname, 0);
8210 if (err)
8211 goto done;
8213 err = got_ref_resolve(branch_tip, repo, commit_ref);
8214 if (err)
8215 goto done;
8216 done:
8217 free(commit_refname);
8218 free(branch_refname);
8219 free(fileindex_path);
8220 if (commit_ref)
8221 got_ref_close(commit_ref);
8222 if (branch_ref)
8223 got_ref_close(branch_ref);
8224 if (err) {
8225 if (*branch_name) {
8226 free(*branch_name);
8227 *branch_name = NULL;
8229 free(*branch_tip);
8230 *branch_tip = NULL;
8231 if (*fileindex) {
8232 got_fileindex_free(*fileindex);
8233 *fileindex = NULL;
8235 lock_worktree(worktree, LOCK_SH);
8237 return err;
8240 const struct got_error *
8241 got_worktree_merge_abort(struct got_worktree *worktree,
8242 struct got_fileindex *fileindex, struct got_repository *repo,
8243 got_worktree_checkout_cb progress_cb, void *progress_arg)
8245 const struct got_error *err, *unlockerr, *sync_err;
8246 struct got_object_id *commit_id = NULL;
8247 struct got_commit_object *commit = NULL;
8248 char *fileindex_path = NULL;
8249 struct revert_file_args rfa;
8250 struct got_object_id *tree_id = NULL;
8252 err = got_object_open_as_commit(&commit, repo,
8253 worktree->base_commit_id);
8254 if (err)
8255 goto done;
8257 err = got_object_id_by_path(&tree_id, repo, commit,
8258 worktree->path_prefix);
8259 if (err)
8260 goto done;
8262 err = delete_merge_refs(worktree, repo);
8263 if (err)
8264 goto done;
8266 err = get_fileindex_path(&fileindex_path, worktree);
8267 if (err)
8268 goto done;
8270 rfa.worktree = worktree;
8271 rfa.fileindex = fileindex;
8272 rfa.progress_cb = progress_cb;
8273 rfa.progress_arg = progress_arg;
8274 rfa.patch_cb = NULL;
8275 rfa.patch_arg = NULL;
8276 rfa.repo = repo;
8277 rfa.unlink_added_files = 1;
8278 err = worktree_status(worktree, "", fileindex, repo,
8279 revert_file, &rfa, NULL, NULL, 1, 0);
8280 if (err)
8281 goto sync;
8283 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
8284 repo, progress_cb, progress_arg, NULL, NULL);
8285 sync:
8286 sync_err = sync_fileindex(fileindex, fileindex_path);
8287 if (sync_err && err == NULL)
8288 err = sync_err;
8289 done:
8290 free(tree_id);
8291 free(commit_id);
8292 if (commit)
8293 got_object_commit_close(commit);
8294 if (fileindex)
8295 got_fileindex_free(fileindex);
8296 free(fileindex_path);
8298 unlockerr = lock_worktree(worktree, LOCK_SH);
8299 if (unlockerr && err == NULL)
8300 err = unlockerr;
8301 return err;
8304 struct check_stage_ok_arg {
8305 struct got_object_id *head_commit_id;
8306 struct got_worktree *worktree;
8307 struct got_fileindex *fileindex;
8308 struct got_repository *repo;
8309 int have_changes;
8312 static const struct got_error *
8313 check_stage_ok(void *arg, unsigned char status,
8314 unsigned char staged_status, const char *relpath,
8315 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
8316 struct got_object_id *commit_id, int dirfd, const char *de_name)
8318 struct check_stage_ok_arg *a = arg;
8319 const struct got_error *err = NULL;
8320 struct got_fileindex_entry *ie;
8321 struct got_object_id base_commit_id;
8322 struct got_object_id *base_commit_idp = NULL;
8323 char *in_repo_path = NULL, *p;
8325 if (status == GOT_STATUS_UNVERSIONED ||
8326 status == GOT_STATUS_NO_CHANGE)
8327 return NULL;
8328 if (status == GOT_STATUS_NONEXISTENT)
8329 return got_error_set_errno(ENOENT, relpath);
8331 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
8332 if (ie == NULL)
8333 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
8335 if (asprintf(&in_repo_path, "%s%s%s", a->worktree->path_prefix,
8336 got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/",
8337 relpath) == -1)
8338 return got_error_from_errno("asprintf");
8340 if (got_fileindex_entry_has_commit(ie)) {
8341 base_commit_idp = got_fileindex_entry_get_commit_id(
8342 &base_commit_id, ie);
8345 if (status == GOT_STATUS_CONFLICT) {
8346 err = got_error_path(ie->path, GOT_ERR_STAGE_CONFLICT);
8347 goto done;
8348 } else if (status != GOT_STATUS_ADD &&
8349 status != GOT_STATUS_MODIFY &&
8350 status != GOT_STATUS_DELETE) {
8351 err = got_error_path(ie->path, GOT_ERR_FILE_STATUS);
8352 goto done;
8355 a->have_changes = 1;
8357 p = in_repo_path;
8358 while (p[0] == '/')
8359 p++;
8360 err = check_out_of_date(p, status, staged_status,
8361 blob_id, base_commit_idp, a->head_commit_id, a->repo,
8362 GOT_ERR_STAGE_OUT_OF_DATE);
8363 done:
8364 free(in_repo_path);
8365 return err;
8368 struct stage_path_arg {
8369 struct got_worktree *worktree;
8370 struct got_fileindex *fileindex;
8371 struct got_repository *repo;
8372 got_worktree_status_cb status_cb;
8373 void *status_arg;
8374 got_worktree_patch_cb patch_cb;
8375 void *patch_arg;
8376 int staged_something;
8377 int allow_bad_symlinks;
8380 static const struct got_error *
8381 stage_path(void *arg, unsigned char status,
8382 unsigned char staged_status, const char *relpath,
8383 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
8384 struct got_object_id *commit_id, int dirfd, const char *de_name)
8386 struct stage_path_arg *a = arg;
8387 const struct got_error *err = NULL;
8388 struct got_fileindex_entry *ie;
8389 char *ondisk_path = NULL, *path_content = NULL;
8390 uint32_t stage;
8391 struct got_object_id *new_staged_blob_id = NULL;
8392 struct stat sb;
8394 if (status == GOT_STATUS_UNVERSIONED)
8395 return NULL;
8397 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
8398 if (ie == NULL)
8399 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
8401 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
8402 relpath)== -1)
8403 return got_error_from_errno("asprintf");
8405 switch (status) {
8406 case GOT_STATUS_ADD:
8407 case GOT_STATUS_MODIFY:
8408 /* XXX could sb.st_mode be passed in by our caller? */
8409 if (lstat(ondisk_path, &sb) == -1) {
8410 err = got_error_from_errno2("lstat", ondisk_path);
8411 break;
8413 if (a->patch_cb) {
8414 if (status == GOT_STATUS_ADD) {
8415 int choice = GOT_PATCH_CHOICE_NONE;
8416 err = (*a->patch_cb)(&choice, a->patch_arg,
8417 status, ie->path, NULL, 1, 1);
8418 if (err)
8419 break;
8420 if (choice != GOT_PATCH_CHOICE_YES)
8421 break;
8422 } else {
8423 err = create_patched_content(&path_content, 0,
8424 staged_blob_id ? staged_blob_id : blob_id,
8425 ondisk_path, dirfd, de_name, ie->path,
8426 a->repo, a->patch_cb, a->patch_arg);
8427 if (err || path_content == NULL)
8428 break;
8431 err = got_object_blob_create(&new_staged_blob_id,
8432 path_content ? path_content : ondisk_path, a->repo);
8433 if (err)
8434 break;
8435 memcpy(ie->staged_blob_sha1, new_staged_blob_id->sha1,
8436 SHA1_DIGEST_LENGTH);
8437 if (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD)
8438 stage = GOT_FILEIDX_STAGE_ADD;
8439 else
8440 stage = GOT_FILEIDX_STAGE_MODIFY;
8441 got_fileindex_entry_stage_set(ie, stage);
8442 if (S_ISLNK(sb.st_mode)) {
8443 int is_bad_symlink = 0;
8444 if (!a->allow_bad_symlinks) {
8445 char target_path[PATH_MAX];
8446 ssize_t target_len;
8447 target_len = readlink(ondisk_path, target_path,
8448 sizeof(target_path));
8449 if (target_len == -1) {
8450 err = got_error_from_errno2("readlink",
8451 ondisk_path);
8452 break;
8454 err = is_bad_symlink_target(&is_bad_symlink,
8455 target_path, target_len, ondisk_path,
8456 a->worktree->root_path);
8457 if (err)
8458 break;
8459 if (is_bad_symlink) {
8460 err = got_error_path(ondisk_path,
8461 GOT_ERR_BAD_SYMLINK);
8462 break;
8465 if (is_bad_symlink)
8466 got_fileindex_entry_staged_filetype_set(ie,
8467 GOT_FILEIDX_MODE_BAD_SYMLINK);
8468 else
8469 got_fileindex_entry_staged_filetype_set(ie,
8470 GOT_FILEIDX_MODE_SYMLINK);
8471 } else {
8472 got_fileindex_entry_staged_filetype_set(ie,
8473 GOT_FILEIDX_MODE_REGULAR_FILE);
8475 a->staged_something = 1;
8476 if (a->status_cb == NULL)
8477 break;
8478 err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE,
8479 get_staged_status(ie), relpath, blob_id,
8480 new_staged_blob_id, NULL, dirfd, de_name);
8481 if (err)
8482 break;
8484 * When staging the reverse of the staged diff,
8485 * implicitly unstage the file.
8487 if (memcmp(ie->staged_blob_sha1, ie->blob_sha1,
8488 sizeof(ie->blob_sha1)) == 0) {
8489 got_fileindex_entry_stage_set(ie,
8490 GOT_FILEIDX_STAGE_NONE);
8492 break;
8493 case GOT_STATUS_DELETE:
8494 if (staged_status == GOT_STATUS_DELETE)
8495 break;
8496 if (a->patch_cb) {
8497 int choice = GOT_PATCH_CHOICE_NONE;
8498 err = (*a->patch_cb)(&choice, a->patch_arg, status,
8499 ie->path, NULL, 1, 1);
8500 if (err)
8501 break;
8502 if (choice == GOT_PATCH_CHOICE_NO)
8503 break;
8504 if (choice != GOT_PATCH_CHOICE_YES) {
8505 err = got_error(GOT_ERR_PATCH_CHOICE);
8506 break;
8509 stage = GOT_FILEIDX_STAGE_DELETE;
8510 got_fileindex_entry_stage_set(ie, stage);
8511 a->staged_something = 1;
8512 if (a->status_cb == NULL)
8513 break;
8514 err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE,
8515 get_staged_status(ie), relpath, NULL, NULL, NULL, dirfd,
8516 de_name);
8517 break;
8518 case GOT_STATUS_NO_CHANGE:
8519 break;
8520 case GOT_STATUS_CONFLICT:
8521 err = got_error_path(relpath, GOT_ERR_STAGE_CONFLICT);
8522 break;
8523 case GOT_STATUS_NONEXISTENT:
8524 err = got_error_set_errno(ENOENT, relpath);
8525 break;
8526 default:
8527 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
8528 break;
8531 if (path_content && unlink(path_content) == -1 && err == NULL)
8532 err = got_error_from_errno2("unlink", path_content);
8533 free(path_content);
8534 free(ondisk_path);
8535 free(new_staged_blob_id);
8536 return err;
8539 const struct got_error *
8540 got_worktree_stage(struct got_worktree *worktree,
8541 struct got_pathlist_head *paths,
8542 got_worktree_status_cb status_cb, void *status_arg,
8543 got_worktree_patch_cb patch_cb, void *patch_arg,
8544 int allow_bad_symlinks, struct got_repository *repo)
8546 const struct got_error *err = NULL, *sync_err, *unlockerr;
8547 struct got_pathlist_entry *pe;
8548 struct got_fileindex *fileindex = NULL;
8549 char *fileindex_path = NULL;
8550 struct got_reference *head_ref = NULL;
8551 struct got_object_id *head_commit_id = NULL;
8552 struct check_stage_ok_arg oka;
8553 struct stage_path_arg spa;
8555 err = lock_worktree(worktree, LOCK_EX);
8556 if (err)
8557 return err;
8559 err = got_ref_open(&head_ref, repo,
8560 got_worktree_get_head_ref_name(worktree), 0);
8561 if (err)
8562 goto done;
8563 err = got_ref_resolve(&head_commit_id, repo, head_ref);
8564 if (err)
8565 goto done;
8566 err = open_fileindex(&fileindex, &fileindex_path, worktree);
8567 if (err)
8568 goto done;
8570 /* Check pre-conditions before staging anything. */
8571 oka.head_commit_id = head_commit_id;
8572 oka.worktree = worktree;
8573 oka.fileindex = fileindex;
8574 oka.repo = repo;
8575 oka.have_changes = 0;
8576 TAILQ_FOREACH(pe, paths, entry) {
8577 err = worktree_status(worktree, pe->path, fileindex, repo,
8578 check_stage_ok, &oka, NULL, NULL, 1, 0);
8579 if (err)
8580 goto done;
8582 if (!oka.have_changes) {
8583 err = got_error(GOT_ERR_STAGE_NO_CHANGE);
8584 goto done;
8587 spa.worktree = worktree;
8588 spa.fileindex = fileindex;
8589 spa.repo = repo;
8590 spa.patch_cb = patch_cb;
8591 spa.patch_arg = patch_arg;
8592 spa.status_cb = status_cb;
8593 spa.status_arg = status_arg;
8594 spa.staged_something = 0;
8595 spa.allow_bad_symlinks = allow_bad_symlinks;
8596 TAILQ_FOREACH(pe, paths, entry) {
8597 err = worktree_status(worktree, pe->path, fileindex, repo,
8598 stage_path, &spa, NULL, NULL, 1, 0);
8599 if (err)
8600 goto done;
8602 if (!spa.staged_something) {
8603 err = got_error(GOT_ERR_STAGE_NO_CHANGE);
8604 goto done;
8607 sync_err = sync_fileindex(fileindex, fileindex_path);
8608 if (sync_err && err == NULL)
8609 err = sync_err;
8610 done:
8611 if (head_ref)
8612 got_ref_close(head_ref);
8613 free(head_commit_id);
8614 free(fileindex_path);
8615 if (fileindex)
8616 got_fileindex_free(fileindex);
8617 unlockerr = lock_worktree(worktree, LOCK_SH);
8618 if (unlockerr && err == NULL)
8619 err = unlockerr;
8620 return err;
8623 struct unstage_path_arg {
8624 struct got_worktree *worktree;
8625 struct got_fileindex *fileindex;
8626 struct got_repository *repo;
8627 got_worktree_checkout_cb progress_cb;
8628 void *progress_arg;
8629 got_worktree_patch_cb patch_cb;
8630 void *patch_arg;
8633 static const struct got_error *
8634 create_unstaged_content(char **path_unstaged_content,
8635 char **path_new_staged_content, struct got_object_id *blob_id,
8636 struct got_object_id *staged_blob_id, const char *relpath,
8637 struct got_repository *repo,
8638 got_worktree_patch_cb patch_cb, void *patch_arg)
8640 const struct got_error *err, *free_err;
8641 struct got_blob_object *blob = NULL, *staged_blob = NULL;
8642 FILE *f1 = NULL, *f2 = NULL, *outfile = NULL, *rejectfile = NULL;
8643 char *path1 = NULL, *path2 = NULL, *label1 = NULL;
8644 struct got_diffreg_result *diffreg_result = NULL;
8645 int line_cur1 = 1, line_cur2 = 1, n = 0, nchunks_used = 0;
8646 int have_content = 0, have_rejected_content = 0, i = 0, nchanges = 0;
8647 int fd1 = -1, fd2 = -1;
8649 *path_unstaged_content = NULL;
8650 *path_new_staged_content = NULL;
8652 err = got_object_id_str(&label1, blob_id);
8653 if (err)
8654 return err;
8656 fd1 = got_opentempfd();
8657 if (fd1 == -1) {
8658 err = got_error_from_errno("got_opentempfd");
8659 goto done;
8661 fd2 = got_opentempfd();
8662 if (fd2 == -1) {
8663 err = got_error_from_errno("got_opentempfd");
8664 goto done;
8667 err = got_object_open_as_blob(&blob, repo, blob_id, 8192, fd1);
8668 if (err)
8669 goto done;
8671 err = got_opentemp_named(&path1, &f1, "got-unstage-blob-base", "");
8672 if (err)
8673 goto done;
8675 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob);
8676 if (err)
8677 goto done;
8679 err = got_object_open_as_blob(&staged_blob, repo, staged_blob_id, 8192,
8680 fd2);
8681 if (err)
8682 goto done;
8684 err = got_opentemp_named(&path2, &f2, "got-unstage-blob-staged", "");
8685 if (err)
8686 goto done;
8688 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f2, staged_blob);
8689 if (err)
8690 goto done;
8692 err = got_diff_files(&diffreg_result, f1, 1, label1, f2, 1,
8693 path2, 3, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS);
8694 if (err)
8695 goto done;
8697 err = got_opentemp_named(path_unstaged_content, &outfile,
8698 "got-unstaged-content", "");
8699 if (err)
8700 goto done;
8701 err = got_opentemp_named(path_new_staged_content, &rejectfile,
8702 "got-new-staged-content", "");
8703 if (err)
8704 goto done;
8706 if (fseek(f1, 0L, SEEK_SET) == -1) {
8707 err = got_ferror(f1, GOT_ERR_IO);
8708 goto done;
8710 if (fseek(f2, 0L, SEEK_SET) == -1) {
8711 err = got_ferror(f2, GOT_ERR_IO);
8712 goto done;
8714 /* Count the number of actual changes in the diff result. */
8715 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
8716 struct diff_chunk_context cc = {};
8717 diff_chunk_context_load_change(&cc, &nchunks_used,
8718 diffreg_result->result, n, 0);
8719 nchanges++;
8721 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
8722 int choice;
8723 err = apply_or_reject_change(&choice, &nchunks_used,
8724 diffreg_result->result, n, relpath, f1, f2,
8725 &line_cur1, &line_cur2,
8726 outfile, rejectfile, ++i, nchanges, patch_cb, patch_arg);
8727 if (err)
8728 goto done;
8729 if (choice == GOT_PATCH_CHOICE_YES)
8730 have_content = 1;
8731 else
8732 have_rejected_content = 1;
8733 if (choice == GOT_PATCH_CHOICE_QUIT)
8734 break;
8736 if (have_content || have_rejected_content)
8737 err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2,
8738 outfile, rejectfile);
8739 done:
8740 free(label1);
8741 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
8742 err = got_error_from_errno("close");
8743 if (blob)
8744 got_object_blob_close(blob);
8745 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
8746 err = got_error_from_errno("close");
8747 if (staged_blob)
8748 got_object_blob_close(staged_blob);
8749 free_err = got_diffreg_result_free(diffreg_result);
8750 if (free_err && err == NULL)
8751 err = free_err;
8752 if (f1 && fclose(f1) == EOF && err == NULL)
8753 err = got_error_from_errno2("fclose", path1);
8754 if (f2 && fclose(f2) == EOF && err == NULL)
8755 err = got_error_from_errno2("fclose", path2);
8756 if (outfile && fclose(outfile) == EOF && err == NULL)
8757 err = got_error_from_errno2("fclose", *path_unstaged_content);
8758 if (rejectfile && fclose(rejectfile) == EOF && err == NULL)
8759 err = got_error_from_errno2("fclose", *path_new_staged_content);
8760 if (path1 && unlink(path1) == -1 && err == NULL)
8761 err = got_error_from_errno2("unlink", path1);
8762 if (path2 && unlink(path2) == -1 && err == NULL)
8763 err = got_error_from_errno2("unlink", path2);
8764 if (err || !have_content) {
8765 if (*path_unstaged_content &&
8766 unlink(*path_unstaged_content) == -1 && err == NULL)
8767 err = got_error_from_errno2("unlink",
8768 *path_unstaged_content);
8769 free(*path_unstaged_content);
8770 *path_unstaged_content = NULL;
8772 if (err || !have_content || !have_rejected_content) {
8773 if (*path_new_staged_content &&
8774 unlink(*path_new_staged_content) == -1 && err == NULL)
8775 err = got_error_from_errno2("unlink",
8776 *path_new_staged_content);
8777 free(*path_new_staged_content);
8778 *path_new_staged_content = NULL;
8780 free(path1);
8781 free(path2);
8782 return err;
8785 static const struct got_error *
8786 unstage_hunks(struct got_object_id *staged_blob_id,
8787 struct got_blob_object *blob_base,
8788 struct got_object_id *blob_id, struct got_fileindex_entry *ie,
8789 const char *ondisk_path, const char *label_orig,
8790 struct got_worktree *worktree, struct got_repository *repo,
8791 got_worktree_patch_cb patch_cb, void *patch_arg,
8792 got_worktree_checkout_cb progress_cb, void *progress_arg)
8794 const struct got_error *err = NULL;
8795 char *path_unstaged_content = NULL;
8796 char *path_new_staged_content = NULL;
8797 char *parent = NULL, *base_path = NULL;
8798 char *blob_base_path = NULL;
8799 struct got_object_id *new_staged_blob_id = NULL;
8800 FILE *f = NULL, *f_base = NULL, *f_deriv2 = NULL;
8801 struct stat sb;
8803 err = create_unstaged_content(&path_unstaged_content,
8804 &path_new_staged_content, blob_id, staged_blob_id,
8805 ie->path, repo, patch_cb, patch_arg);
8806 if (err)
8807 return err;
8809 if (path_unstaged_content == NULL)
8810 return NULL;
8812 if (path_new_staged_content) {
8813 err = got_object_blob_create(&new_staged_blob_id,
8814 path_new_staged_content, repo);
8815 if (err)
8816 goto done;
8819 f = fopen(path_unstaged_content, "re");
8820 if (f == NULL) {
8821 err = got_error_from_errno2("fopen",
8822 path_unstaged_content);
8823 goto done;
8825 if (fstat(fileno(f), &sb) == -1) {
8826 err = got_error_from_errno2("fstat", path_unstaged_content);
8827 goto done;
8829 if (got_fileindex_entry_staged_filetype_get(ie) ==
8830 GOT_FILEIDX_MODE_SYMLINK && sb.st_size < PATH_MAX) {
8831 char link_target[PATH_MAX];
8832 size_t r;
8833 r = fread(link_target, 1, sizeof(link_target), f);
8834 if (r == 0 && ferror(f)) {
8835 err = got_error_from_errno("fread");
8836 goto done;
8838 if (r >= sizeof(link_target)) { /* should not happen */
8839 err = got_error(GOT_ERR_NO_SPACE);
8840 goto done;
8842 link_target[r] = '\0';
8843 err = merge_symlink(worktree, blob_base,
8844 ondisk_path, ie->path, label_orig, link_target,
8845 worktree->base_commit_id, repo, progress_cb,
8846 progress_arg);
8847 } else {
8848 int local_changes_subsumed;
8850 err = got_path_dirname(&parent, ondisk_path);
8851 if (err)
8852 return err;
8854 if (asprintf(&base_path, "%s/got-unstage-blob-orig",
8855 parent) == -1) {
8856 err = got_error_from_errno("asprintf");
8857 base_path = NULL;
8858 goto done;
8861 err = got_opentemp_named(&blob_base_path, &f_base,
8862 base_path, "");
8863 if (err)
8864 goto done;
8865 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_base,
8866 blob_base);
8867 if (err)
8868 goto done;
8871 * In order the run a 3-way merge with a symlink we copy the symlink's
8872 * target path into a temporary file and use that file with diff3.
8874 if (S_ISLNK(got_fileindex_perms_to_st(ie))) {
8875 err = dump_symlink_target_path_to_file(&f_deriv2,
8876 ondisk_path);
8877 if (err)
8878 goto done;
8879 } else {
8880 int fd;
8881 fd = open(ondisk_path,
8882 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
8883 if (fd == -1) {
8884 err = got_error_from_errno2("open", ondisk_path);
8885 goto done;
8887 f_deriv2 = fdopen(fd, "r");
8888 if (f_deriv2 == NULL) {
8889 err = got_error_from_errno2("fdopen", ondisk_path);
8890 close(fd);
8891 goto done;
8895 err = merge_file(&local_changes_subsumed, worktree,
8896 f_base, f, f_deriv2, ondisk_path, ie->path,
8897 got_fileindex_perms_to_st(ie),
8898 label_orig, "unstaged", NULL, GOT_DIFF_ALGORITHM_MYERS,
8899 repo, progress_cb, progress_arg);
8901 if (err)
8902 goto done;
8904 if (new_staged_blob_id) {
8905 memcpy(ie->staged_blob_sha1, new_staged_blob_id->sha1,
8906 SHA1_DIGEST_LENGTH);
8907 } else {
8908 got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
8909 got_fileindex_entry_staged_filetype_set(ie, 0);
8911 done:
8912 free(new_staged_blob_id);
8913 if (path_unstaged_content &&
8914 unlink(path_unstaged_content) == -1 && err == NULL)
8915 err = got_error_from_errno2("unlink", path_unstaged_content);
8916 if (path_new_staged_content &&
8917 unlink(path_new_staged_content) == -1 && err == NULL)
8918 err = got_error_from_errno2("unlink", path_new_staged_content);
8919 if (blob_base_path && unlink(blob_base_path) == -1 && err == NULL)
8920 err = got_error_from_errno2("unlink", blob_base_path);
8921 if (f_base && fclose(f_base) == EOF && err == NULL)
8922 err = got_error_from_errno2("fclose", path_unstaged_content);
8923 if (f && fclose(f) == EOF && err == NULL)
8924 err = got_error_from_errno2("fclose", path_unstaged_content);
8925 if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL)
8926 err = got_error_from_errno2("fclose", ondisk_path);
8927 free(path_unstaged_content);
8928 free(path_new_staged_content);
8929 free(blob_base_path);
8930 free(parent);
8931 free(base_path);
8932 return err;
8935 static const struct got_error *
8936 unstage_path(void *arg, unsigned char status,
8937 unsigned char staged_status, const char *relpath,
8938 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
8939 struct got_object_id *commit_id, int dirfd, const char *de_name)
8941 const struct got_error *err = NULL;
8942 struct unstage_path_arg *a = arg;
8943 struct got_fileindex_entry *ie;
8944 struct got_blob_object *blob_base = NULL, *blob_staged = NULL;
8945 char *ondisk_path = NULL;
8946 char *id_str = NULL, *label_orig = NULL;
8947 int local_changes_subsumed;
8948 struct stat sb;
8949 int fd1 = -1, fd2 = -1;
8951 if (staged_status != GOT_STATUS_ADD &&
8952 staged_status != GOT_STATUS_MODIFY &&
8953 staged_status != GOT_STATUS_DELETE)
8954 return NULL;
8956 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
8957 if (ie == NULL)
8958 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
8960 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, relpath)
8961 == -1)
8962 return got_error_from_errno("asprintf");
8964 err = got_object_id_str(&id_str,
8965 commit_id ? commit_id : a->worktree->base_commit_id);
8966 if (err)
8967 goto done;
8968 if (asprintf(&label_orig, "%s: commit %s", GOT_MERGE_LABEL_BASE,
8969 id_str) == -1) {
8970 err = got_error_from_errno("asprintf");
8971 goto done;
8974 fd1 = got_opentempfd();
8975 if (fd1 == -1) {
8976 err = got_error_from_errno("got_opentempfd");
8977 goto done;
8979 fd2 = got_opentempfd();
8980 if (fd2 == -1) {
8981 err = got_error_from_errno("got_opentempfd");
8982 goto done;
8985 switch (staged_status) {
8986 case GOT_STATUS_MODIFY:
8987 err = got_object_open_as_blob(&blob_base, a->repo,
8988 blob_id, 8192, fd1);
8989 if (err)
8990 break;
8991 /* fall through */
8992 case GOT_STATUS_ADD:
8993 if (a->patch_cb) {
8994 if (staged_status == GOT_STATUS_ADD) {
8995 int choice = GOT_PATCH_CHOICE_NONE;
8996 err = (*a->patch_cb)(&choice, a->patch_arg,
8997 staged_status, ie->path, NULL, 1, 1);
8998 if (err)
8999 break;
9000 if (choice != GOT_PATCH_CHOICE_YES)
9001 break;
9002 } else {
9003 err = unstage_hunks(staged_blob_id,
9004 blob_base, blob_id, ie, ondisk_path,
9005 label_orig, a->worktree, a->repo,
9006 a->patch_cb, a->patch_arg,
9007 a->progress_cb, a->progress_arg);
9008 break; /* Done with this file. */
9011 err = got_object_open_as_blob(&blob_staged, a->repo,
9012 staged_blob_id, 8192, fd2);
9013 if (err)
9014 break;
9015 switch (got_fileindex_entry_staged_filetype_get(ie)) {
9016 case GOT_FILEIDX_MODE_BAD_SYMLINK:
9017 case GOT_FILEIDX_MODE_REGULAR_FILE:
9018 err = merge_blob(&local_changes_subsumed, a->worktree,
9019 blob_base, ondisk_path, relpath,
9020 got_fileindex_perms_to_st(ie), label_orig,
9021 blob_staged, commit_id ? commit_id :
9022 a->worktree->base_commit_id, a->repo,
9023 a->progress_cb, a->progress_arg);
9024 break;
9025 case GOT_FILEIDX_MODE_SYMLINK:
9026 if (S_ISLNK(got_fileindex_perms_to_st(ie))) {
9027 char *staged_target;
9028 err = got_object_blob_read_to_str(
9029 &staged_target, blob_staged);
9030 if (err)
9031 goto done;
9032 err = merge_symlink(a->worktree, blob_base,
9033 ondisk_path, relpath, label_orig,
9034 staged_target, commit_id ? commit_id :
9035 a->worktree->base_commit_id,
9036 a->repo, a->progress_cb, a->progress_arg);
9037 free(staged_target);
9038 } else {
9039 err = merge_blob(&local_changes_subsumed,
9040 a->worktree, blob_base, ondisk_path,
9041 relpath, got_fileindex_perms_to_st(ie),
9042 label_orig, blob_staged,
9043 commit_id ? commit_id :
9044 a->worktree->base_commit_id, a->repo,
9045 a->progress_cb, a->progress_arg);
9047 break;
9048 default:
9049 err = got_error_path(relpath, GOT_ERR_BAD_FILETYPE);
9050 break;
9052 if (err == NULL) {
9053 got_fileindex_entry_stage_set(ie,
9054 GOT_FILEIDX_STAGE_NONE);
9055 got_fileindex_entry_staged_filetype_set(ie, 0);
9057 break;
9058 case GOT_STATUS_DELETE:
9059 if (a->patch_cb) {
9060 int choice = GOT_PATCH_CHOICE_NONE;
9061 err = (*a->patch_cb)(&choice, a->patch_arg,
9062 staged_status, ie->path, NULL, 1, 1);
9063 if (err)
9064 break;
9065 if (choice == GOT_PATCH_CHOICE_NO)
9066 break;
9067 if (choice != GOT_PATCH_CHOICE_YES) {
9068 err = got_error(GOT_ERR_PATCH_CHOICE);
9069 break;
9072 got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
9073 got_fileindex_entry_staged_filetype_set(ie, 0);
9074 err = get_file_status(&status, &sb, ie, ondisk_path,
9075 dirfd, de_name, a->repo);
9076 if (err)
9077 break;
9078 err = (*a->progress_cb)(a->progress_arg, status, relpath);
9079 break;
9081 done:
9082 free(ondisk_path);
9083 if (fd1 != -1 && close(fd1) == -1 && err == NULL)
9084 err = got_error_from_errno("close");
9085 if (blob_base)
9086 got_object_blob_close(blob_base);
9087 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
9088 err = got_error_from_errno("close");
9089 if (blob_staged)
9090 got_object_blob_close(blob_staged);
9091 free(id_str);
9092 free(label_orig);
9093 return err;
9096 const struct got_error *
9097 got_worktree_unstage(struct got_worktree *worktree,
9098 struct got_pathlist_head *paths,
9099 got_worktree_checkout_cb progress_cb, void *progress_arg,
9100 got_worktree_patch_cb patch_cb, void *patch_arg,
9101 struct got_repository *repo)
9103 const struct got_error *err = NULL, *sync_err, *unlockerr;
9104 struct got_pathlist_entry *pe;
9105 struct got_fileindex *fileindex = NULL;
9106 char *fileindex_path = NULL;
9107 struct unstage_path_arg upa;
9109 err = lock_worktree(worktree, LOCK_EX);
9110 if (err)
9111 return err;
9113 err = open_fileindex(&fileindex, &fileindex_path, worktree);
9114 if (err)
9115 goto done;
9117 upa.worktree = worktree;
9118 upa.fileindex = fileindex;
9119 upa.repo = repo;
9120 upa.progress_cb = progress_cb;
9121 upa.progress_arg = progress_arg;
9122 upa.patch_cb = patch_cb;
9123 upa.patch_arg = patch_arg;
9124 TAILQ_FOREACH(pe, paths, entry) {
9125 err = worktree_status(worktree, pe->path, fileindex, repo,
9126 unstage_path, &upa, NULL, NULL, 1, 0);
9127 if (err)
9128 goto done;
9131 sync_err = sync_fileindex(fileindex, fileindex_path);
9132 if (sync_err && err == NULL)
9133 err = sync_err;
9134 done:
9135 free(fileindex_path);
9136 if (fileindex)
9137 got_fileindex_free(fileindex);
9138 unlockerr = lock_worktree(worktree, LOCK_SH);
9139 if (unlockerr && err == NULL)
9140 err = unlockerr;
9141 return err;
9144 struct report_file_info_arg {
9145 struct got_worktree *worktree;
9146 got_worktree_path_info_cb info_cb;
9147 void *info_arg;
9148 struct got_pathlist_head *paths;
9149 got_cancel_cb cancel_cb;
9150 void *cancel_arg;
9153 static const struct got_error *
9154 report_file_info(void *arg, struct got_fileindex_entry *ie)
9156 struct report_file_info_arg *a = arg;
9157 struct got_pathlist_entry *pe;
9158 struct got_object_id blob_id, staged_blob_id, commit_id;
9159 struct got_object_id *blob_idp = NULL, *staged_blob_idp = NULL;
9160 struct got_object_id *commit_idp = NULL;
9161 int stage;
9163 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
9164 return got_error(GOT_ERR_CANCELLED);
9166 TAILQ_FOREACH(pe, a->paths, entry) {
9167 if (pe->path_len == 0 || strcmp(pe->path, ie->path) == 0 ||
9168 got_path_is_child(ie->path, pe->path, pe->path_len))
9169 break;
9171 if (pe == NULL) /* not found */
9172 return NULL;
9174 if (got_fileindex_entry_has_blob(ie))
9175 blob_idp = got_fileindex_entry_get_blob_id(&blob_id, ie);
9176 stage = got_fileindex_entry_stage_get(ie);
9177 if (stage == GOT_FILEIDX_STAGE_MODIFY ||
9178 stage == GOT_FILEIDX_STAGE_ADD) {
9179 staged_blob_idp = got_fileindex_entry_get_staged_blob_id(
9180 &staged_blob_id, ie);
9183 if (got_fileindex_entry_has_commit(ie))
9184 commit_idp = got_fileindex_entry_get_commit_id(&commit_id, ie);
9186 return a->info_cb(a->info_arg, ie->path, got_fileindex_perms_to_st(ie),
9187 (time_t)ie->mtime_sec, blob_idp, staged_blob_idp, commit_idp);
9190 const struct got_error *
9191 got_worktree_path_info(struct got_worktree *worktree,
9192 struct got_pathlist_head *paths,
9193 got_worktree_path_info_cb info_cb, void *info_arg,
9194 got_cancel_cb cancel_cb, void *cancel_arg)
9197 const struct got_error *err = NULL, *unlockerr;
9198 struct got_fileindex *fileindex = NULL;
9199 char *fileindex_path = NULL;
9200 struct report_file_info_arg arg;
9202 err = lock_worktree(worktree, LOCK_SH);
9203 if (err)
9204 return err;
9206 err = open_fileindex(&fileindex, &fileindex_path, worktree);
9207 if (err)
9208 goto done;
9210 arg.worktree = worktree;
9211 arg.info_cb = info_cb;
9212 arg.info_arg = info_arg;
9213 arg.paths = paths;
9214 arg.cancel_cb = cancel_cb;
9215 arg.cancel_arg = cancel_arg;
9216 err = got_fileindex_for_each_entry_safe(fileindex, report_file_info,
9217 &arg);
9218 done:
9219 free(fileindex_path);
9220 if (fileindex)
9221 got_fileindex_free(fileindex);
9222 unlockerr = lock_worktree(worktree, LOCK_UN);
9223 if (unlockerr && err == NULL)
9224 err = unlockerr;
9225 return err;
9228 static const struct got_error *
9229 patch_check_path(const char *p, char **path, unsigned char *status,
9230 unsigned char *staged_status, struct got_fileindex *fileindex,
9231 struct got_worktree *worktree, struct got_repository *repo)
9233 const struct got_error *err;
9234 struct got_fileindex_entry *ie;
9235 struct stat sb;
9236 char *ondisk_path = NULL;
9238 err = got_worktree_resolve_path(path, worktree, p);
9239 if (err)
9240 return err;
9242 if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path,
9243 *path[0] ? "/" : "", *path) == -1)
9244 return got_error_from_errno("asprintf");
9246 ie = got_fileindex_entry_get(fileindex, *path, strlen(*path));
9247 if (ie) {
9248 *staged_status = get_staged_status(ie);
9249 err = get_file_status(status, &sb, ie, ondisk_path, -1, NULL,
9250 repo);
9251 if (err)
9252 goto done;
9253 } else {
9254 *staged_status = GOT_STATUS_NO_CHANGE;
9255 *status = GOT_STATUS_UNVERSIONED;
9256 if (lstat(ondisk_path, &sb) == -1) {
9257 if (errno != ENOENT) {
9258 err = got_error_from_errno2("lstat",
9259 ondisk_path);
9260 goto done;
9262 *status = GOT_STATUS_NONEXISTENT;
9266 done:
9267 free(ondisk_path);
9268 return err;
9271 static const struct got_error *
9272 patch_can_rm(const char *path, unsigned char status,
9273 unsigned char staged_status)
9275 if (status == GOT_STATUS_NONEXISTENT)
9276 return got_error_set_errno(ENOENT, path);
9277 if (status != GOT_STATUS_NO_CHANGE &&
9278 status != GOT_STATUS_ADD &&
9279 status != GOT_STATUS_MODIFY &&
9280 status != GOT_STATUS_MODE_CHANGE)
9281 return got_error_path(path, GOT_ERR_FILE_STATUS);
9282 if (staged_status == GOT_STATUS_DELETE)
9283 return got_error_path(path, GOT_ERR_FILE_STATUS);
9284 return NULL;
9287 static const struct got_error *
9288 patch_can_add(const char *path, unsigned char status)
9290 if (status != GOT_STATUS_NONEXISTENT)
9291 return got_error_path(path, GOT_ERR_FILE_STATUS);
9292 return NULL;
9295 static const struct got_error *
9296 patch_can_edit(const char *path, unsigned char status,
9297 unsigned char staged_status)
9299 if (status == GOT_STATUS_NONEXISTENT)
9300 return got_error_set_errno(ENOENT, path);
9301 if (status != GOT_STATUS_NO_CHANGE &&
9302 status != GOT_STATUS_ADD &&
9303 status != GOT_STATUS_MODIFY)
9304 return got_error_path(path, GOT_ERR_FILE_STATUS);
9305 if (staged_status == GOT_STATUS_DELETE)
9306 return got_error_path(path, GOT_ERR_FILE_STATUS);
9307 return NULL;
9310 const struct got_error *
9311 got_worktree_patch_prepare(struct got_fileindex **fileindex,
9312 char **fileindex_path, struct got_worktree *worktree)
9314 return open_fileindex(fileindex, fileindex_path, worktree);
9317 const struct got_error *
9318 got_worktree_patch_check_path(const char *old, const char *new,
9319 char **oldpath, char **newpath, struct got_worktree *worktree,
9320 struct got_repository *repo, struct got_fileindex *fileindex)
9322 const struct got_error *err = NULL;
9323 int file_renamed = 0;
9324 unsigned char status_old, staged_status_old;
9325 unsigned char status_new, staged_status_new;
9327 *oldpath = NULL;
9328 *newpath = NULL;
9330 err = patch_check_path(old != NULL ? old : new, oldpath,
9331 &status_old, &staged_status_old, fileindex, worktree, repo);
9332 if (err)
9333 goto done;
9335 err = patch_check_path(new != NULL ? new : old, newpath,
9336 &status_new, &staged_status_new, fileindex, worktree, repo);
9337 if (err)
9338 goto done;
9340 if (old != NULL && new != NULL && strcmp(old, new) != 0)
9341 file_renamed = 1;
9343 if (old != NULL && new == NULL)
9344 err = patch_can_rm(*oldpath, status_old, staged_status_old);
9345 else if (file_renamed) {
9346 err = patch_can_rm(*oldpath, status_old, staged_status_old);
9347 if (err == NULL)
9348 err = patch_can_add(*newpath, status_new);
9349 } else if (old == NULL)
9350 err = patch_can_add(*newpath, status_new);
9351 else
9352 err = patch_can_edit(*newpath, status_new, staged_status_new);
9354 done:
9355 if (err) {
9356 free(*oldpath);
9357 *oldpath = NULL;
9358 free(*newpath);
9359 *newpath = NULL;
9361 return err;
9364 const struct got_error *
9365 got_worktree_patch_schedule_add(const char *path, struct got_repository *repo,
9366 struct got_worktree *worktree, struct got_fileindex *fileindex,
9367 got_worktree_checkout_cb progress_cb, void *progress_arg)
9369 struct schedule_addition_args saa;
9371 memset(&saa, 0, sizeof(saa));
9372 saa.worktree = worktree;
9373 saa.fileindex = fileindex;
9374 saa.progress_cb = progress_cb;
9375 saa.progress_arg = progress_arg;
9376 saa.repo = repo;
9378 return worktree_status(worktree, path, fileindex, repo,
9379 schedule_addition, &saa, NULL, NULL, 1, 0);
9382 const struct got_error *
9383 got_worktree_patch_schedule_rm(const char *path, struct got_repository *repo,
9384 struct got_worktree *worktree, struct got_fileindex *fileindex,
9385 got_worktree_delete_cb progress_cb, void *progress_arg)
9387 struct schedule_deletion_args sda;
9389 memset(&sda, 0, sizeof(sda));
9390 sda.worktree = worktree;
9391 sda.fileindex = fileindex;
9392 sda.progress_cb = progress_cb;
9393 sda.progress_arg = progress_arg;
9394 sda.repo = repo;
9395 sda.delete_local_mods = 0;
9396 sda.keep_on_disk = 0;
9397 sda.ignore_missing_paths = 0;
9398 sda.status_codes = NULL;
9400 return worktree_status(worktree, path, fileindex, repo,
9401 schedule_for_deletion, &sda, NULL, NULL, 1, 1);
9404 const struct got_error *
9405 got_worktree_patch_complete(struct got_fileindex *fileindex,
9406 const char *fileindex_path)
9408 const struct got_error *err = NULL;
9410 err = sync_fileindex(fileindex, fileindex_path);
9411 got_fileindex_free(fileindex);
9413 return err;