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 const struct got_error *
68 create_meta_file(const char *path_got, const char *name, const char *content)
69 {
70 const struct got_error *err = NULL;
71 char *path;
73 if (asprintf(&path, "%s/%s", path_got, name) == -1)
74 return got_error_from_errno("asprintf");
76 err = got_path_create_file(path, content);
77 free(path);
78 return err;
79 }
81 static const struct got_error *
82 update_meta_file(const char *path_got, const char *name, const char *content)
83 {
84 const struct got_error *err = NULL;
85 FILE *tmpfile = NULL;
86 char *tmppath = NULL;
87 char *path = NULL;
89 if (asprintf(&path, "%s/%s", path_got, name) == -1) {
90 err = got_error_from_errno("asprintf");
91 path = NULL;
92 goto done;
93 }
95 err = got_opentemp_named(&tmppath, &tmpfile, path);
96 if (err)
97 goto done;
99 if (content) {
100 int len = fprintf(tmpfile, "%s\n", content);
101 if (len != strlen(content) + 1) {
102 err = got_error_from_errno2("fprintf", tmppath);
103 goto done;
107 if (rename(tmppath, path) != 0) {
108 err = got_error_from_errno3("rename", tmppath, path);
109 unlink(tmppath);
110 goto done;
113 done:
114 if (fclose(tmpfile) != 0 && err == NULL)
115 err = got_error_from_errno2("fclose", tmppath);
116 free(tmppath);
117 return err;
120 static const struct got_error *
121 read_meta_file(char **content, const char *path_got, const char *name)
123 const struct got_error *err = NULL;
124 char *path;
125 int fd = -1;
126 ssize_t n;
127 struct stat sb;
129 *content = NULL;
131 if (asprintf(&path, "%s/%s", path_got, name) == -1) {
132 err = got_error_from_errno("asprintf");
133 path = NULL;
134 goto done;
137 fd = open(path, O_RDONLY | O_NOFOLLOW);
138 if (fd == -1) {
139 if (errno == ENOENT)
140 err = got_error_path(path, GOT_ERR_WORKTREE_META);
141 else
142 err = got_error_from_errno2("open", path);
143 goto done;
145 if (flock(fd, LOCK_SH | LOCK_NB) == -1) {
146 err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY)
147 : got_error_from_errno2("flock", path));
148 goto done;
151 if (fstat(fd, &sb) != 0) {
152 err = got_error_from_errno2("fstat", path);
153 goto done;
155 *content = calloc(1, sb.st_size);
156 if (*content == NULL) {
157 err = got_error_from_errno("calloc");
158 goto done;
161 n = read(fd, *content, sb.st_size);
162 if (n != sb.st_size) {
163 err = (n == -1 ? got_error_from_errno2("read", path) :
164 got_error_path(path, GOT_ERR_WORKTREE_META));
165 goto done;
167 if ((*content)[sb.st_size - 1] != '\n') {
168 err = got_error_path(path, GOT_ERR_WORKTREE_META);
169 goto done;
171 (*content)[sb.st_size - 1] = '\0';
173 done:
174 if (fd != -1 && close(fd) == -1 && err == NULL)
175 err = got_error_from_errno2("close", path_got);
176 free(path);
177 if (err) {
178 free(*content);
179 *content = NULL;
181 return err;
184 static const struct got_error *
185 write_head_ref(const char *path_got, struct got_reference *head_ref)
187 const struct got_error *err = NULL;
188 char *refstr = NULL;
190 if (got_ref_is_symbolic(head_ref)) {
191 refstr = got_ref_to_str(head_ref);
192 if (refstr == NULL)
193 return got_error_from_errno("got_ref_to_str");
194 } else {
195 refstr = strdup(got_ref_get_name(head_ref));
196 if (refstr == NULL)
197 return got_error_from_errno("strdup");
199 err = update_meta_file(path_got, GOT_WORKTREE_HEAD_REF, refstr);
200 free(refstr);
201 return err;
204 const struct got_error *
205 got_worktree_init(const char *path, struct got_reference *head_ref,
206 const char *prefix, struct got_repository *repo)
208 const struct got_error *err = NULL;
209 struct got_object_id *commit_id = NULL;
210 uuid_t uuid;
211 uint32_t uuid_status;
212 int obj_type;
213 char *path_got = NULL;
214 char *formatstr = NULL;
215 char *absprefix = NULL;
216 char *basestr = NULL;
217 char *uuidstr = NULL;
219 if (strcmp(path, got_repo_get_path(repo)) == 0) {
220 err = got_error(GOT_ERR_WORKTREE_REPO);
221 goto done;
224 err = got_ref_resolve(&commit_id, repo, head_ref);
225 if (err)
226 return err;
227 err = got_object_get_type(&obj_type, repo, commit_id);
228 if (err)
229 return err;
230 if (obj_type != GOT_OBJ_TYPE_COMMIT)
231 return got_error(GOT_ERR_OBJ_TYPE);
233 if (!got_path_is_absolute(prefix)) {
234 if (asprintf(&absprefix, "/%s", prefix) == -1)
235 return got_error_from_errno("asprintf");
238 /* Create top-level directory (may already exist). */
239 if (mkdir(path, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
240 err = got_error_from_errno2("mkdir", path);
241 goto done;
244 /* Create .got directory (may already exist). */
245 if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) {
246 err = got_error_from_errno("asprintf");
247 goto done;
249 if (mkdir(path_got, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
250 err = got_error_from_errno2("mkdir", path_got);
251 goto done;
254 /* Create an empty lock file. */
255 err = create_meta_file(path_got, GOT_WORKTREE_LOCK, NULL);
256 if (err)
257 goto done;
259 /* Create an empty file index. */
260 err = create_meta_file(path_got, GOT_WORKTREE_FILE_INDEX, NULL);
261 if (err)
262 goto done;
264 /* Write the HEAD reference. */
265 err = write_head_ref(path_got, head_ref);
266 if (err)
267 goto done;
269 /* Record our base commit. */
270 err = got_object_id_str(&basestr, commit_id);
271 if (err)
272 goto done;
273 err = create_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, basestr);
274 if (err)
275 goto done;
277 /* Store path to repository. */
278 err = create_meta_file(path_got, GOT_WORKTREE_REPOSITORY,
279 got_repo_get_path(repo));
280 if (err)
281 goto done;
283 /* Store in-repository path prefix. */
284 err = create_meta_file(path_got, GOT_WORKTREE_PATH_PREFIX,
285 absprefix ? absprefix : prefix);
286 if (err)
287 goto done;
289 /* Generate UUID. */
290 uuid_create(&uuid, &uuid_status);
291 if (uuid_status != uuid_s_ok) {
292 err = got_error_uuid(uuid_status, "uuid_create");
293 goto done;
295 uuid_to_string(&uuid, &uuidstr, &uuid_status);
296 if (uuid_status != uuid_s_ok) {
297 err = got_error_uuid(uuid_status, "uuid_to_string");
298 goto done;
300 err = create_meta_file(path_got, GOT_WORKTREE_UUID, uuidstr);
301 if (err)
302 goto done;
304 /* Stamp work tree with format file. */
305 if (asprintf(&formatstr, "%d", GOT_WORKTREE_FORMAT_VERSION) == -1) {
306 err = got_error_from_errno("asprintf");
307 goto done;
309 err = create_meta_file(path_got, GOT_WORKTREE_FORMAT, formatstr);
310 if (err)
311 goto done;
313 done:
314 free(commit_id);
315 free(path_got);
316 free(formatstr);
317 free(absprefix);
318 free(basestr);
319 free(uuidstr);
320 return err;
323 static const struct got_error *
324 open_worktree(struct got_worktree **worktree, const char *path)
326 const struct got_error *err = NULL;
327 char *path_got;
328 char *formatstr = NULL;
329 char *uuidstr = NULL;
330 char *path_lock = NULL;
331 char *base_commit_id_str = NULL;
332 int version, fd = -1;
333 const char *errstr;
334 struct got_repository *repo = NULL;
335 uint32_t uuid_status;
337 *worktree = NULL;
339 if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) {
340 err = got_error_from_errno("asprintf");
341 path_got = NULL;
342 goto done;
345 if (asprintf(&path_lock, "%s/%s", path_got, GOT_WORKTREE_LOCK) == -1) {
346 err = got_error_from_errno("asprintf");
347 path_lock = NULL;
348 goto done;
351 fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK);
352 if (fd == -1) {
353 err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY)
354 : got_error_from_errno2("open", path_lock));
355 goto done;
358 err = read_meta_file(&formatstr, path_got, GOT_WORKTREE_FORMAT);
359 if (err)
360 goto done;
362 version = strtonum(formatstr, 1, INT_MAX, &errstr);
363 if (errstr) {
364 err = got_error_msg(GOT_ERR_WORKTREE_META,
365 "could not parse work tree format version number");
366 goto done;
368 if (version != GOT_WORKTREE_FORMAT_VERSION) {
369 err = got_error(GOT_ERR_WORKTREE_VERS);
370 goto done;
373 *worktree = calloc(1, sizeof(**worktree));
374 if (*worktree == NULL) {
375 err = got_error_from_errno("calloc");
376 goto done;
378 (*worktree)->lockfd = -1;
380 (*worktree)->root_path = realpath(path, NULL);
381 if ((*worktree)->root_path == NULL) {
382 err = got_error_from_errno2("realpath", path);
383 goto done;
385 err = read_meta_file(&(*worktree)->repo_path, path_got,
386 GOT_WORKTREE_REPOSITORY);
387 if (err)
388 goto done;
390 err = read_meta_file(&(*worktree)->path_prefix, path_got,
391 GOT_WORKTREE_PATH_PREFIX);
392 if (err)
393 goto done;
395 err = read_meta_file(&base_commit_id_str, path_got,
396 GOT_WORKTREE_BASE_COMMIT);
397 if (err)
398 goto done;
400 err = read_meta_file(&uuidstr, path_got, GOT_WORKTREE_UUID);
401 if (err)
402 goto done;
403 uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status);
404 if (uuid_status != uuid_s_ok) {
405 err = got_error_uuid(uuid_status, "uuid_from_string");
406 goto done;
409 err = got_repo_open(&repo, (*worktree)->repo_path, NULL);
410 if (err)
411 goto done;
413 err = got_object_resolve_id_str(&(*worktree)->base_commit_id, repo,
414 base_commit_id_str);
415 if (err)
416 goto done;
418 err = read_meta_file(&(*worktree)->head_ref_name, path_got,
419 GOT_WORKTREE_HEAD_REF);
420 if (err)
421 goto done;
423 if (asprintf(&(*worktree)->gotconfig_path, "%s/%s/%s",
424 (*worktree)->root_path,
425 GOT_WORKTREE_GOT_DIR, GOT_GOTCONFIG_FILENAME) == -1) {
426 err = got_error_from_errno("asprintf");
427 goto done;
430 err = got_gotconfig_read(&(*worktree)->gotconfig,
431 (*worktree)->gotconfig_path);
433 (*worktree)->root_fd = open((*worktree)->root_path, O_DIRECTORY);
434 if ((*worktree)->root_fd == -1) {
435 err = got_error_from_errno2("open", (*worktree)->root_path);
436 goto done;
438 done:
439 if (repo)
440 got_repo_close(repo);
441 free(path_got);
442 free(path_lock);
443 free(base_commit_id_str);
444 free(uuidstr);
445 free(formatstr);
446 if (err) {
447 if (fd != -1)
448 close(fd);
449 if (*worktree != NULL)
450 got_worktree_close(*worktree);
451 *worktree = NULL;
452 } else
453 (*worktree)->lockfd = fd;
455 return err;
458 const struct got_error *
459 got_worktree_open(struct got_worktree **worktree, const char *path)
461 const struct got_error *err = NULL;
462 char *worktree_path;
464 worktree_path = strdup(path);
465 if (worktree_path == NULL)
466 return got_error_from_errno("strdup");
468 for (;;) {
469 char *parent_path;
471 err = open_worktree(worktree, worktree_path);
472 if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) {
473 free(worktree_path);
474 return err;
476 if (*worktree) {
477 free(worktree_path);
478 return NULL;
480 if (worktree_path[0] == '/' && worktree_path[1] == '\0')
481 break;
482 err = got_path_dirname(&parent_path, worktree_path);
483 if (err) {
484 if (err->code != GOT_ERR_BAD_PATH) {
485 free(worktree_path);
486 return err;
488 break;
490 free(worktree_path);
491 worktree_path = parent_path;
494 free(worktree_path);
495 return got_error(GOT_ERR_NOT_WORKTREE);
498 const struct got_error *
499 got_worktree_close(struct got_worktree *worktree)
501 const struct got_error *err = NULL;
502 free(worktree->repo_path);
503 free(worktree->path_prefix);
504 free(worktree->base_commit_id);
505 free(worktree->head_ref_name);
506 if (worktree->lockfd != -1)
507 if (close(worktree->lockfd) != 0)
508 err = got_error_from_errno2("close",
509 got_worktree_get_root_path(worktree));
510 free(worktree->root_path);
511 free(worktree->gotconfig_path);
512 got_gotconfig_free(worktree->gotconfig);
513 free(worktree);
514 close(worktree->root_fd);
515 return err;
518 const char *
519 got_worktree_get_root_path(struct got_worktree *worktree)
521 return worktree->root_path;
524 const char *
525 got_worktree_get_repo_path(struct got_worktree *worktree)
527 return worktree->repo_path;
529 const char *
530 got_worktree_get_path_prefix(struct got_worktree *worktree)
532 return worktree->path_prefix;
535 const struct got_error *
536 got_worktree_match_path_prefix(int *match, struct got_worktree *worktree,
537 const char *path_prefix)
539 char *absprefix = NULL;
541 if (!got_path_is_absolute(path_prefix)) {
542 if (asprintf(&absprefix, "/%s", path_prefix) == -1)
543 return got_error_from_errno("asprintf");
545 *match = (strcmp(absprefix ? absprefix : path_prefix,
546 worktree->path_prefix) == 0);
547 free(absprefix);
548 return NULL;
551 const char *
552 got_worktree_get_head_ref_name(struct got_worktree *worktree)
554 return worktree->head_ref_name;
557 const struct got_error *
558 got_worktree_set_head_ref(struct got_worktree *worktree,
559 struct got_reference *head_ref)
561 const struct got_error *err = NULL;
562 char *path_got = NULL, *head_ref_name = NULL;
564 if (asprintf(&path_got, "%s/%s", worktree->root_path,
565 GOT_WORKTREE_GOT_DIR) == -1) {
566 err = got_error_from_errno("asprintf");
567 path_got = NULL;
568 goto done;
571 head_ref_name = strdup(got_ref_get_name(head_ref));
572 if (head_ref_name == NULL) {
573 err = got_error_from_errno("strdup");
574 goto done;
577 err = write_head_ref(path_got, head_ref);
578 if (err)
579 goto done;
581 free(worktree->head_ref_name);
582 worktree->head_ref_name = head_ref_name;
583 done:
584 free(path_got);
585 if (err)
586 free(head_ref_name);
587 return err;
590 struct got_object_id *
591 got_worktree_get_base_commit_id(struct got_worktree *worktree)
593 return worktree->base_commit_id;
596 const struct got_error *
597 got_worktree_set_base_commit_id(struct got_worktree *worktree,
598 struct got_repository *repo, struct got_object_id *commit_id)
600 const struct got_error *err;
601 struct got_object *obj = NULL;
602 char *id_str = NULL;
603 char *path_got = NULL;
605 if (asprintf(&path_got, "%s/%s", worktree->root_path,
606 GOT_WORKTREE_GOT_DIR) == -1) {
607 err = got_error_from_errno("asprintf");
608 path_got = NULL;
609 goto done;
612 err = got_object_open(&obj, repo, commit_id);
613 if (err)
614 return err;
616 if (obj->type != GOT_OBJ_TYPE_COMMIT) {
617 err = got_error(GOT_ERR_OBJ_TYPE);
618 goto done;
621 /* Record our base commit. */
622 err = got_object_id_str(&id_str, commit_id);
623 if (err)
624 goto done;
625 err = update_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, id_str);
626 if (err)
627 goto done;
629 free(worktree->base_commit_id);
630 worktree->base_commit_id = got_object_id_dup(commit_id);
631 if (worktree->base_commit_id == NULL) {
632 err = got_error_from_errno("got_object_id_dup");
633 goto done;
635 done:
636 if (obj)
637 got_object_close(obj);
638 free(id_str);
639 free(path_got);
640 return err;
643 const struct got_gotconfig *
644 got_worktree_get_gotconfig(struct got_worktree *worktree)
646 return worktree->gotconfig;
649 static const struct got_error *
650 lock_worktree(struct got_worktree *worktree, int operation)
652 if (flock(worktree->lockfd, operation | LOCK_NB) == -1)
653 return (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY)
654 : got_error_from_errno2("flock",
655 got_worktree_get_root_path(worktree)));
656 return NULL;
659 static const struct got_error *
660 add_dir_on_disk(struct got_worktree *worktree, const char *path)
662 const struct got_error *err = NULL;
663 char *abspath;
665 if (asprintf(&abspath, "%s/%s", worktree->root_path, path) == -1)
666 return got_error_from_errno("asprintf");
668 err = got_path_mkdir(abspath);
669 if (err && err->code == GOT_ERR_ERRNO && errno == EEXIST) {
670 struct stat sb;
671 err = NULL;
672 if (lstat(abspath, &sb) == -1) {
673 err = got_error_from_errno2("lstat", abspath);
674 } else if (!S_ISDIR(sb.st_mode)) {
675 /* TODO directory is obstructed; do something */
676 err = got_error_path(abspath, GOT_ERR_FILE_OBSTRUCTED);
679 free(abspath);
680 return err;
683 static const struct got_error *
684 check_file_contents_equal(int *same, FILE *f1, FILE *f2)
686 const struct got_error *err = NULL;
687 uint8_t fbuf1[8192];
688 uint8_t fbuf2[8192];
689 size_t flen1 = 0, flen2 = 0;
691 *same = 1;
693 for (;;) {
694 flen1 = fread(fbuf1, 1, sizeof(fbuf1), f1);
695 if (flen1 == 0 && ferror(f1)) {
696 err = got_error_from_errno("fread");
697 break;
699 flen2 = fread(fbuf2, 1, sizeof(fbuf2), f2);
700 if (flen2 == 0 && ferror(f2)) {
701 err = got_error_from_errno("fread");
702 break;
704 if (flen1 == 0) {
705 if (flen2 != 0)
706 *same = 0;
707 break;
708 } else if (flen2 == 0) {
709 if (flen1 != 0)
710 *same = 0;
711 break;
712 } else if (flen1 == flen2) {
713 if (memcmp(fbuf1, fbuf2, flen2) != 0) {
714 *same = 0;
715 break;
717 } else {
718 *same = 0;
719 break;
723 return err;
726 static const struct got_error *
727 check_files_equal(int *same, const char *f1_path, const char *f2_path)
729 const struct got_error *err = NULL;
730 struct stat sb;
731 size_t size1, size2;
732 FILE *f1 = NULL, *f2 = NULL;
734 *same = 1;
736 if (lstat(f1_path, &sb) != 0) {
737 err = got_error_from_errno2("lstat", f1_path);
738 goto done;
740 size1 = sb.st_size;
742 if (lstat(f2_path, &sb) != 0) {
743 err = got_error_from_errno2("lstat", f2_path);
744 goto done;
746 size2 = sb.st_size;
748 if (size1 != size2) {
749 *same = 0;
750 return NULL;
753 f1 = fopen(f1_path, "r");
754 if (f1 == NULL)
755 return got_error_from_errno2("fopen", f1_path);
757 f2 = fopen(f2_path, "r");
758 if (f2 == NULL) {
759 err = got_error_from_errno2("fopen", f2_path);
760 goto done;
763 err = check_file_contents_equal(same, f1, f2);
764 done:
765 if (f1 && fclose(f1) != 0 && err == NULL)
766 err = got_error_from_errno("fclose");
767 if (f2 && fclose(f2) != 0 && err == NULL)
768 err = got_error_from_errno("fclose");
770 return err;
773 /*
774 * Perform a 3-way merge where blob_orig acts as the common ancestor,
775 * the file at deriv_path acts as the first derived version, and the
776 * file on disk acts as the second derived version.
777 */
778 static const struct got_error *
779 merge_file(int *local_changes_subsumed, struct got_worktree *worktree,
780 struct got_blob_object *blob_orig, const char *ondisk_path,
781 const char *path, uint16_t st_mode, const char *deriv_path,
782 const char *label_orig, const char *label_deriv,
783 struct got_repository *repo,
784 got_worktree_checkout_cb progress_cb, void *progress_arg)
786 const struct got_error *err = NULL;
787 int merged_fd = -1;
788 FILE *f_orig = NULL;
789 char *blob_orig_path = NULL;
790 char *merged_path = NULL, *base_path = NULL;
791 int overlapcnt = 0;
792 char *parent = NULL;
793 char *symlink_path = NULL;
794 FILE *symlinkf = NULL;
796 *local_changes_subsumed = 0;
798 err = got_path_dirname(&parent, ondisk_path);
799 if (err)
800 return err;
802 if (asprintf(&base_path, "%s/got-merged", parent) == -1) {
803 err = got_error_from_errno("asprintf");
804 goto done;
807 err = got_opentemp_named_fd(&merged_path, &merged_fd, base_path);
808 if (err)
809 goto done;
811 free(base_path);
812 if (asprintf(&base_path, "%s/got-merge-blob-orig", parent) == -1) {
813 err = got_error_from_errno("asprintf");
814 base_path = NULL;
815 goto done;
818 err = got_opentemp_named(&blob_orig_path, &f_orig, base_path);
819 if (err)
820 goto done;
821 if (blob_orig) {
822 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_orig,
823 blob_orig);
824 if (err)
825 goto done;
826 } else {
827 /*
828 * If the file has no blob, this is an "add vs add" conflict,
829 * and we simply use an empty ancestor file to make both files
830 * appear in the merged result in their entirety.
831 */
834 /*
835 * In order the run a 3-way merge with a symlink we copy the symlink's
836 * target path into a temporary file and use that file with diff3.
837 */
838 if (S_ISLNK(st_mode)) {
839 char target_path[PATH_MAX];
840 ssize_t target_len;
841 size_t n;
843 free(base_path);
844 if (asprintf(&base_path, "%s/got-symlink-merge",
845 parent) == -1) {
846 err = got_error_from_errno("asprintf");
847 base_path = NULL;
848 goto done;
850 err = got_opentemp_named(&symlink_path, &symlinkf, base_path);
851 if (err)
852 goto done;
853 target_len = readlink(ondisk_path, target_path,
854 sizeof(target_path));
855 if (target_len == -1) {
856 err = got_error_from_errno2("readlink", ondisk_path);
857 goto done;
859 n = fwrite(target_path, 1, target_len, symlinkf);
860 if (n != target_len) {
861 err = got_ferror(symlinkf, GOT_ERR_IO);
862 goto done;
864 if (fflush(symlinkf) == EOF) {
865 err = got_error_from_errno2("fflush", symlink_path);
866 goto done;
870 err = got_merge_diff3(&overlapcnt, merged_fd, deriv_path,
871 blob_orig_path, symlink_path ? symlink_path : ondisk_path,
872 label_deriv, label_orig, NULL);
873 if (err)
874 goto done;
876 err = (*progress_cb)(progress_arg,
877 overlapcnt > 0 ? GOT_STATUS_CONFLICT : GOT_STATUS_MERGE, path);
878 if (err)
879 goto done;
881 if (fsync(merged_fd) != 0) {
882 err = got_error_from_errno("fsync");
883 goto done;
886 /* Check if a clean merge has subsumed all local changes. */
887 if (overlapcnt == 0) {
888 err = check_files_equal(local_changes_subsumed, deriv_path,
889 merged_path);
890 if (err)
891 goto done;
894 if (fchmod(merged_fd, st_mode) != 0) {
895 err = got_error_from_errno2("fchmod", merged_path);
896 goto done;
899 if (rename(merged_path, ondisk_path) != 0) {
900 err = got_error_from_errno3("rename", merged_path,
901 ondisk_path);
902 goto done;
904 done:
905 if (err) {
906 if (merged_path)
907 unlink(merged_path);
909 if (symlink_path) {
910 if (unlink(symlink_path) == -1 && err == NULL)
911 err = got_error_from_errno2("unlink", symlink_path);
913 if (symlinkf && fclose(symlinkf) == EOF && err == NULL)
914 err = got_error_from_errno2("fclose", symlink_path);
915 free(symlink_path);
916 if (merged_fd != -1 && close(merged_fd) != 0 && err == NULL)
917 err = got_error_from_errno("close");
918 if (f_orig && fclose(f_orig) != 0 && err == NULL)
919 err = got_error_from_errno("fclose");
920 free(merged_path);
921 free(base_path);
922 if (blob_orig_path) {
923 unlink(blob_orig_path);
924 free(blob_orig_path);
926 free(parent);
927 return err;
930 static const struct got_error *
931 update_symlink(const char *ondisk_path, const char *target_path,
932 size_t target_len)
934 /* This is not atomic but matches what 'ln -sf' does. */
935 if (unlink(ondisk_path) == -1)
936 return got_error_from_errno2("unlink", ondisk_path);
937 if (symlink(target_path, ondisk_path) == -1)
938 return got_error_from_errno3("symlink", target_path,
939 ondisk_path);
940 return NULL;
943 /*
944 * Overwrite a symlink (or a regular file in case there was a "bad" symlink)
945 * in the work tree with a file that contains conflict markers and the
946 * conflicting target paths of the original version, a "derived version"
947 * of a symlink from an incoming change, and a local version of the symlink.
949 * The original versions's target path can be NULL if it is not available,
950 * such as if both derived versions added a new symlink at the same path.
952 * The incoming derived symlink target is NULL in case the incoming change
953 * has deleted this symlink.
954 */
955 static const struct got_error *
956 install_symlink_conflict(const char *deriv_target,
957 struct got_object_id *deriv_base_commit_id, const char *orig_target,
958 const char *label_orig, const char *local_target, const char *ondisk_path)
960 const struct got_error *err;
961 char *id_str = NULL, *label_deriv = NULL, *path = NULL;
962 FILE *f = NULL;
964 err = got_object_id_str(&id_str, deriv_base_commit_id);
965 if (err)
966 return got_error_from_errno("asprintf");
968 if (asprintf(&label_deriv, "%s: commit %s",
969 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
970 err = got_error_from_errno("asprintf");
971 goto done;
974 err = got_opentemp_named(&path, &f, "got-symlink-conflict");
975 if (err)
976 goto done;
978 if (fchmod(fileno(f), GOT_DEFAULT_FILE_MODE) == -1) {
979 err = got_error_from_errno2("fchmod", path);
980 goto done;
983 if (fprintf(f, "%s %s\n%s\n%s%s%s%s%s\n%s\n%s\n",
984 GOT_DIFF_CONFLICT_MARKER_BEGIN, label_deriv,
985 deriv_target ? deriv_target : "(symlink was deleted)",
986 orig_target ? label_orig : "",
987 orig_target ? "\n" : "",
988 orig_target ? orig_target : "",
989 orig_target ? "\n" : "",
990 GOT_DIFF_CONFLICT_MARKER_SEP,
991 local_target, GOT_DIFF_CONFLICT_MARKER_END) < 0) {
992 err = got_error_from_errno2("fprintf", path);
993 goto done;
996 if (unlink(ondisk_path) == -1) {
997 err = got_error_from_errno2("unlink", ondisk_path);
998 goto done;
1000 if (rename(path, ondisk_path) == -1) {
1001 err = got_error_from_errno3("rename", path, ondisk_path);
1002 goto done;
1004 done:
1005 if (f != NULL && fclose(f) == EOF && err == NULL)
1006 err = got_error_from_errno2("fclose", path);
1007 free(path);
1008 free(id_str);
1009 free(label_deriv);
1010 return err;
1013 /* forward declaration */
1014 static const struct got_error *
1015 merge_blob(int *, struct got_worktree *, struct got_blob_object *,
1016 const char *, const char *, uint16_t, const char *,
1017 struct got_blob_object *, struct got_object_id *,
1018 struct got_repository *, got_worktree_checkout_cb, void *);
1021 * Merge a symlink into the work tree, where blob_orig acts as the common
1022 * ancestor, deriv_target is the link target of the first derived version,
1023 * and the symlink on disk acts as the second derived version.
1024 * Assume that contents of both blobs represent symlinks.
1026 static const struct got_error *
1027 merge_symlink(struct got_worktree *worktree,
1028 struct got_blob_object *blob_orig, const char *ondisk_path,
1029 const char *path, const char *label_orig, const char *deriv_target,
1030 struct got_object_id *deriv_base_commit_id, struct got_repository *repo,
1031 got_worktree_checkout_cb progress_cb, void *progress_arg)
1033 const struct got_error *err = NULL;
1034 char *ancestor_target = NULL;
1035 struct stat sb;
1036 ssize_t ondisk_len, deriv_len;
1037 char ondisk_target[PATH_MAX];
1038 int have_local_change = 0;
1039 int have_incoming_change = 0;
1041 if (lstat(ondisk_path, &sb) == -1)
1042 return got_error_from_errno2("lstat", ondisk_path);
1044 ondisk_len = readlink(ondisk_path, ondisk_target,
1045 sizeof(ondisk_target));
1046 if (ondisk_len == -1) {
1047 err = got_error_from_errno2("readlink",
1048 ondisk_path);
1049 goto done;
1051 ondisk_target[ondisk_len] = '\0';
1053 if (blob_orig) {
1054 err = got_object_blob_read_to_str(&ancestor_target, blob_orig);
1055 if (err)
1056 goto done;
1059 if (ancestor_target == NULL ||
1060 (ondisk_len != strlen(ancestor_target) ||
1061 memcmp(ondisk_target, ancestor_target, ondisk_len) != 0))
1062 have_local_change = 1;
1064 deriv_len = strlen(deriv_target);
1065 if (ancestor_target == NULL ||
1066 (deriv_len != strlen(ancestor_target) ||
1067 memcmp(deriv_target, ancestor_target, deriv_len) != 0))
1068 have_incoming_change = 1;
1070 if (!have_local_change && !have_incoming_change) {
1071 if (ancestor_target) {
1072 /* Both sides made the same change. */
1073 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
1074 path);
1075 } else if (deriv_len == ondisk_len &&
1076 memcmp(ondisk_target, deriv_target, deriv_len) == 0) {
1077 /* Both sides added the same symlink. */
1078 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
1079 path);
1080 } else {
1081 /* Both sides added symlinks which don't match. */
1082 err = install_symlink_conflict(deriv_target,
1083 deriv_base_commit_id, ancestor_target,
1084 label_orig, ondisk_target, ondisk_path);
1085 if (err)
1086 goto done;
1087 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
1088 path);
1090 } else if (!have_local_change && have_incoming_change) {
1091 /* Apply the incoming change. */
1092 err = update_symlink(ondisk_path, deriv_target,
1093 strlen(deriv_target));
1094 if (err)
1095 goto done;
1096 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
1097 } else if (have_local_change && have_incoming_change) {
1098 if (deriv_len == ondisk_len &&
1099 memcmp(deriv_target, ondisk_target, deriv_len) == 0) {
1100 /* Both sides made the same change. */
1101 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE,
1102 path);
1103 } else {
1104 err = install_symlink_conflict(deriv_target,
1105 deriv_base_commit_id, ancestor_target, label_orig,
1106 ondisk_target, ondisk_path);
1107 if (err)
1108 goto done;
1109 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
1110 path);
1114 done:
1115 free(ancestor_target);
1116 return err;
1120 * Perform a 3-way merge where blob_orig acts as the common ancestor,
1121 * blob_deriv acts as the first derived version, and the file on disk
1122 * acts as the second derived version.
1124 static const struct got_error *
1125 merge_blob(int *local_changes_subsumed, struct got_worktree *worktree,
1126 struct got_blob_object *blob_orig, const char *ondisk_path,
1127 const char *path, uint16_t st_mode, const char *label_orig,
1128 struct got_blob_object *blob_deriv,
1129 struct got_object_id *deriv_base_commit_id, struct got_repository *repo,
1130 got_worktree_checkout_cb progress_cb, void *progress_arg)
1132 const struct got_error *err = NULL;
1133 FILE *f_deriv = NULL;
1134 char *blob_deriv_path = NULL, *base_path = NULL, *id_str = NULL;
1135 char *label_deriv = NULL, *parent = NULL;
1137 *local_changes_subsumed = 0;
1139 err = got_path_dirname(&parent, ondisk_path);
1140 if (err)
1141 return err;
1143 free(base_path);
1144 if (asprintf(&base_path, "%s/got-merge-blob-deriv", parent) == -1) {
1145 err = got_error_from_errno("asprintf");
1146 base_path = NULL;
1147 goto done;
1150 err = got_opentemp_named(&blob_deriv_path, &f_deriv, base_path);
1151 if (err)
1152 goto done;
1153 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_deriv,
1154 blob_deriv);
1155 if (err)
1156 goto done;
1158 err = got_object_id_str(&id_str, deriv_base_commit_id);
1159 if (err)
1160 goto done;
1161 if (asprintf(&label_deriv, "%s: commit %s",
1162 GOT_MERGE_LABEL_MERGED, id_str) == -1) {
1163 err = got_error_from_errno("asprintf");
1164 goto done;
1167 err = merge_file(local_changes_subsumed, worktree, blob_orig,
1168 ondisk_path, path, st_mode, blob_deriv_path, label_orig,
1169 label_deriv, repo, progress_cb, progress_arg);
1170 done:
1171 if (f_deriv && fclose(f_deriv) != 0 && err == NULL)
1172 err = got_error_from_errno("fclose");
1173 free(base_path);
1174 if (blob_deriv_path) {
1175 unlink(blob_deriv_path);
1176 free(blob_deriv_path);
1178 free(id_str);
1179 free(label_deriv);
1180 free(parent);
1181 return err;
1184 static const struct got_error *
1185 create_fileindex_entry(struct got_fileindex_entry **new_iep,
1186 struct got_fileindex *fileindex, struct got_object_id *base_commit_id,
1187 int wt_fd, const char *path, struct got_object_id *blob_id)
1189 const struct got_error *err = NULL;
1190 struct got_fileindex_entry *new_ie;
1192 *new_iep = NULL;
1194 err = got_fileindex_entry_alloc(&new_ie, path);
1195 if (err)
1196 return err;
1198 err = got_fileindex_entry_update(new_ie, wt_fd, path,
1199 blob_id->sha1, base_commit_id->sha1, 1);
1200 if (err)
1201 goto done;
1203 err = got_fileindex_entry_add(fileindex, new_ie);
1204 done:
1205 if (err)
1206 got_fileindex_entry_free(new_ie);
1207 else
1208 *new_iep = new_ie;
1209 return err;
1212 static mode_t
1213 get_ondisk_perms(int executable, mode_t st_mode)
1215 mode_t xbits = S_IXUSR;
1217 if (executable) {
1218 /* Map read bits to execute bits. */
1219 if (st_mode & S_IRGRP)
1220 xbits |= S_IXGRP;
1221 if (st_mode & S_IROTH)
1222 xbits |= S_IXOTH;
1223 return st_mode | xbits;
1226 return (st_mode & ~(S_IXUSR | S_IXGRP | S_IXOTH));
1229 /* forward declaration */
1230 static const struct got_error *
1231 install_blob(struct got_worktree *worktree, const char *ondisk_path,
1232 const char *path, mode_t te_mode, mode_t st_mode,
1233 struct got_blob_object *blob, int restoring_missing_file,
1234 int reverting_versioned_file, int installing_bad_symlink,
1235 int path_is_unversioned, struct got_repository *repo,
1236 got_worktree_checkout_cb progress_cb, void *progress_arg);
1239 * This function assumes that the provided symlink target points at a
1240 * safe location in the work tree!
1242 static const struct got_error *
1243 replace_existing_symlink(const char *ondisk_path, const char *target_path,
1244 size_t target_len)
1246 const struct got_error *err = NULL;
1247 ssize_t elen;
1248 char etarget[PATH_MAX];
1249 int fd;
1252 * "Bad" symlinks (those pointing outside the work tree or into the
1253 * .got directory) are installed in the work tree as a regular file
1254 * which contains the bad symlink target path.
1255 * The new symlink target has already been checked for safety by our
1256 * caller. If we can successfully open a regular file then we simply
1257 * replace this file with a symlink below.
1259 fd = open(ondisk_path, O_RDWR | O_EXCL | O_NOFOLLOW);
1260 if (fd == -1) {
1261 if (errno != ELOOP)
1262 return got_error_from_errno2("open", ondisk_path);
1264 /* We are updating an existing on-disk symlink. */
1265 elen = readlink(ondisk_path, etarget, sizeof(etarget));
1266 if (elen == -1)
1267 return got_error_from_errno2("readlink", ondisk_path);
1269 if (elen == target_len &&
1270 memcmp(etarget, target_path, target_len) == 0)
1271 return NULL; /* nothing to do */
1274 err = update_symlink(ondisk_path, target_path, target_len);
1275 if (fd != -1 && close(fd) == -1 && err == NULL)
1276 err = got_error_from_errno2("close", ondisk_path);
1277 return err;
1280 static const struct got_error *
1281 is_bad_symlink_target(int *is_bad_symlink, const char *target_path,
1282 size_t target_len, const char *ondisk_path, const char *wtroot_path)
1284 const struct got_error *err = NULL;
1285 char canonpath[PATH_MAX];
1286 char *path_got = NULL;
1288 *is_bad_symlink = 0;
1290 if (target_len >= sizeof(canonpath)) {
1291 *is_bad_symlink = 1;
1292 return NULL;
1296 * We do not use realpath(3) to resolve the symlink's target
1297 * path because we don't want to resolve symlinks recursively.
1298 * Instead we make the path absolute and then canonicalize it.
1299 * Relative symlink target lookup should begin at the directory
1300 * in which the blob object is being installed.
1302 if (!got_path_is_absolute(target_path)) {
1303 char *abspath, *parent;
1304 err = got_path_dirname(&parent, ondisk_path);
1305 if (err)
1306 return err;
1307 if (asprintf(&abspath, "%s/%s", parent, target_path) == -1) {
1308 free(parent);
1309 return got_error_from_errno("asprintf");
1311 free(parent);
1312 if (strlen(abspath) >= sizeof(canonpath)) {
1313 err = got_error_path(abspath, GOT_ERR_BAD_PATH);
1314 free(abspath);
1315 return err;
1317 err = got_canonpath(abspath, canonpath, sizeof(canonpath));
1318 free(abspath);
1319 if (err)
1320 return err;
1321 } else {
1322 err = got_canonpath(target_path, canonpath, sizeof(canonpath));
1323 if (err)
1324 return err;
1327 /* Only allow symlinks pointing at paths within the work tree. */
1328 if (!got_path_is_child(canonpath, wtroot_path, strlen(wtroot_path))) {
1329 *is_bad_symlink = 1;
1330 return NULL;
1333 /* Do not allow symlinks pointing into the .got directory. */
1334 if (asprintf(&path_got, "%s/%s", wtroot_path,
1335 GOT_WORKTREE_GOT_DIR) == -1)
1336 return got_error_from_errno("asprintf");
1337 if (got_path_is_child(canonpath, path_got, strlen(path_got)))
1338 *is_bad_symlink = 1;
1340 free(path_got);
1341 return NULL;
1344 static const struct got_error *
1345 install_symlink(int *is_bad_symlink, struct got_worktree *worktree,
1346 const char *ondisk_path, const char *path, struct got_blob_object *blob,
1347 int restoring_missing_file, int reverting_versioned_file,
1348 int path_is_unversioned, struct got_repository *repo,
1349 got_worktree_checkout_cb progress_cb, void *progress_arg)
1351 const struct got_error *err = NULL;
1352 char target_path[PATH_MAX];
1353 size_t len, target_len = 0;
1354 char *path_got = NULL;
1355 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1356 size_t hdrlen = got_object_blob_get_hdrlen(blob);
1358 *is_bad_symlink = 0;
1361 * Blob object content specifies the target path of the link.
1362 * If a symbolic link cannot be installed we instead create
1363 * a regular file which contains the link target path stored
1364 * in the blob object.
1366 do {
1367 err = got_object_blob_read_block(&len, blob);
1368 if (len + target_len >= sizeof(target_path)) {
1369 /* Path too long; install as a regular file. */
1370 *is_bad_symlink = 1;
1371 got_object_blob_rewind(blob);
1372 return install_blob(worktree, ondisk_path, path,
1373 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1374 restoring_missing_file, reverting_versioned_file,
1375 1, path_is_unversioned, repo, progress_cb,
1376 progress_arg);
1378 if (len > 0) {
1379 /* Skip blob object header first time around. */
1380 memcpy(target_path + target_len, buf + hdrlen,
1381 len - hdrlen);
1382 target_len += len - hdrlen;
1383 hdrlen = 0;
1385 } while (len != 0);
1386 target_path[target_len] = '\0';
1388 err = is_bad_symlink_target(is_bad_symlink, target_path, target_len,
1389 ondisk_path, worktree->root_path);
1390 if (err)
1391 return err;
1393 if (*is_bad_symlink) {
1394 /* install as a regular file */
1395 *is_bad_symlink = 1;
1396 got_object_blob_rewind(blob);
1397 err = install_blob(worktree, ondisk_path, path,
1398 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1399 restoring_missing_file, reverting_versioned_file, 1,
1400 path_is_unversioned, repo, progress_cb, progress_arg);
1401 goto done;
1404 if (symlink(target_path, ondisk_path) == -1) {
1405 if (errno == EEXIST) {
1406 if (path_is_unversioned) {
1407 err = (*progress_cb)(progress_arg,
1408 GOT_STATUS_UNVERSIONED, path);
1409 goto done;
1411 err = replace_existing_symlink(ondisk_path,
1412 target_path, target_len);
1413 if (err)
1414 goto done;
1415 if (progress_cb) {
1416 err = (*progress_cb)(progress_arg,
1417 reverting_versioned_file ?
1418 GOT_STATUS_REVERT : GOT_STATUS_UPDATE,
1419 path);
1421 goto done; /* Nothing else to do. */
1424 if (errno == ENOENT) {
1425 char *parent;
1426 err = got_path_dirname(&parent, ondisk_path);
1427 if (err)
1428 goto done;
1429 err = add_dir_on_disk(worktree, parent);
1430 free(parent);
1431 if (err)
1432 goto done;
1434 * Retry, and fall through to error handling
1435 * below if this second attempt fails.
1437 if (symlink(target_path, ondisk_path) != -1) {
1438 err = NULL; /* success */
1439 goto done;
1443 /* Handle errors from first or second creation attempt. */
1444 if (errno == ENAMETOOLONG) {
1445 /* bad target path; install as a regular file */
1446 *is_bad_symlink = 1;
1447 got_object_blob_rewind(blob);
1448 err = install_blob(worktree, ondisk_path, path,
1449 GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
1450 restoring_missing_file, reverting_versioned_file, 1,
1451 path_is_unversioned, repo,
1452 progress_cb, progress_arg);
1453 } else if (errno == ENOTDIR) {
1454 err = got_error_path(ondisk_path,
1455 GOT_ERR_FILE_OBSTRUCTED);
1456 } else {
1457 err = got_error_from_errno3("symlink",
1458 target_path, ondisk_path);
1460 } else if (progress_cb)
1461 err = (*progress_cb)(progress_arg, reverting_versioned_file ?
1462 GOT_STATUS_REVERT : GOT_STATUS_ADD, path);
1463 done:
1464 free(path_got);
1465 return err;
1468 static const struct got_error *
1469 install_blob(struct got_worktree *worktree, const char *ondisk_path,
1470 const char *path, mode_t te_mode, mode_t st_mode,
1471 struct got_blob_object *blob, int restoring_missing_file,
1472 int reverting_versioned_file, int installing_bad_symlink,
1473 int path_is_unversioned, struct got_repository *repo,
1474 got_worktree_checkout_cb progress_cb, void *progress_arg)
1476 const struct got_error *err = NULL;
1477 int fd = -1;
1478 size_t len, hdrlen;
1479 int update = 0;
1480 char *tmppath = NULL;
1482 fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW,
1483 GOT_DEFAULT_FILE_MODE);
1484 if (fd == -1) {
1485 if (errno == ENOENT) {
1486 char *parent;
1487 err = got_path_dirname(&parent, path);
1488 if (err)
1489 return err;
1490 err = add_dir_on_disk(worktree, parent);
1491 free(parent);
1492 if (err)
1493 return err;
1494 fd = open(ondisk_path,
1495 O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW,
1496 GOT_DEFAULT_FILE_MODE);
1497 if (fd == -1)
1498 return got_error_from_errno2("open",
1499 ondisk_path);
1500 } else if (errno == EEXIST) {
1501 if (path_is_unversioned) {
1502 err = (*progress_cb)(progress_arg,
1503 GOT_STATUS_UNVERSIONED, path);
1504 goto done;
1506 if (!(S_ISLNK(st_mode) && S_ISREG(te_mode)) &&
1507 !S_ISREG(st_mode) && !installing_bad_symlink) {
1508 /* TODO file is obstructed; do something */
1509 err = got_error_path(ondisk_path,
1510 GOT_ERR_FILE_OBSTRUCTED);
1511 goto done;
1512 } else {
1513 err = got_opentemp_named_fd(&tmppath, &fd,
1514 ondisk_path);
1515 if (err)
1516 goto done;
1517 update = 1;
1519 } else
1520 return got_error_from_errno2("open", ondisk_path);
1523 if (fchmod(fd, get_ondisk_perms(te_mode & S_IXUSR, st_mode)) == -1) {
1524 err = got_error_from_errno2("fchmod",
1525 update ? tmppath : ondisk_path);
1526 goto done;
1529 if (progress_cb) {
1530 if (restoring_missing_file)
1531 err = (*progress_cb)(progress_arg, GOT_STATUS_MISSING,
1532 path);
1533 else if (reverting_versioned_file)
1534 err = (*progress_cb)(progress_arg, GOT_STATUS_REVERT,
1535 path);
1536 else
1537 err = (*progress_cb)(progress_arg,
1538 update ? GOT_STATUS_UPDATE : GOT_STATUS_ADD, path);
1539 if (err)
1540 goto done;
1543 hdrlen = got_object_blob_get_hdrlen(blob);
1544 do {
1545 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1546 err = got_object_blob_read_block(&len, blob);
1547 if (err)
1548 break;
1549 if (len > 0) {
1550 /* Skip blob object header first time around. */
1551 ssize_t outlen = write(fd, buf + hdrlen, len - hdrlen);
1552 if (outlen == -1) {
1553 err = got_error_from_errno("write");
1554 goto done;
1555 } else if (outlen != len - hdrlen) {
1556 err = got_error(GOT_ERR_IO);
1557 goto done;
1559 hdrlen = 0;
1561 } while (len != 0);
1563 if (fsync(fd) != 0) {
1564 err = got_error_from_errno("fsync");
1565 goto done;
1568 if (update) {
1569 if (S_ISLNK(st_mode) && unlink(ondisk_path) == -1) {
1570 err = got_error_from_errno2("unlink", ondisk_path);
1571 goto done;
1573 if (rename(tmppath, ondisk_path) != 0) {
1574 err = got_error_from_errno3("rename", tmppath,
1575 ondisk_path);
1576 goto done;
1578 free(tmppath);
1579 tmppath = NULL;
1582 done:
1583 if (fd != -1 && close(fd) != 0 && err == NULL)
1584 err = got_error_from_errno("close");
1585 if (tmppath != NULL && unlink(tmppath) == -1 && err == NULL)
1586 err = got_error_from_errno2("unlink", tmppath);
1587 free(tmppath);
1588 return err;
1591 /* Upgrade STATUS_MODIFY to STATUS_CONFLICT if a conflict marker is found. */
1592 static const struct got_error *
1593 get_modified_file_content_status(unsigned char *status, FILE *f)
1595 const struct got_error *err = NULL;
1596 const char *markers[3] = {
1597 GOT_DIFF_CONFLICT_MARKER_BEGIN,
1598 GOT_DIFF_CONFLICT_MARKER_SEP,
1599 GOT_DIFF_CONFLICT_MARKER_END
1601 int i = 0;
1602 char *line;
1603 size_t len;
1604 const char delim[3] = {'\0', '\0', '\0'};
1606 while (*status == GOT_STATUS_MODIFY) {
1607 line = fparseln(f, &len, NULL, delim, 0);
1608 if (line == NULL) {
1609 if (feof(f))
1610 break;
1611 err = got_ferror(f, GOT_ERR_IO);
1612 break;
1615 if (strncmp(line, markers[i], strlen(markers[i])) == 0) {
1616 if (strcmp(markers[i], GOT_DIFF_CONFLICT_MARKER_END)
1617 == 0)
1618 *status = GOT_STATUS_CONFLICT;
1619 else
1620 i++;
1624 return err;
1627 static int
1628 xbit_differs(struct got_fileindex_entry *ie, uint16_t st_mode)
1630 mode_t ie_mode = got_fileindex_perms_to_st(ie);
1631 return ((ie_mode & S_IXUSR) != (st_mode & S_IXUSR));
1634 static int
1635 stat_info_differs(struct got_fileindex_entry *ie, struct stat *sb)
1637 return !(ie->ctime_sec == sb->st_ctim.tv_sec &&
1638 ie->ctime_nsec == sb->st_ctim.tv_nsec &&
1639 ie->mtime_sec == sb->st_mtim.tv_sec &&
1640 ie->mtime_nsec == sb->st_mtim.tv_nsec &&
1641 ie->size == (sb->st_size & 0xffffffff) &&
1642 !xbit_differs(ie, sb->st_mode));
1645 static unsigned char
1646 get_staged_status(struct got_fileindex_entry *ie)
1648 switch (got_fileindex_entry_stage_get(ie)) {
1649 case GOT_FILEIDX_STAGE_ADD:
1650 return GOT_STATUS_ADD;
1651 case GOT_FILEIDX_STAGE_DELETE:
1652 return GOT_STATUS_DELETE;
1653 case GOT_FILEIDX_STAGE_MODIFY:
1654 return GOT_STATUS_MODIFY;
1655 default:
1656 return GOT_STATUS_NO_CHANGE;
1660 static const struct got_error *
1661 get_symlink_modification_status(unsigned char *status,
1662 struct got_fileindex_entry *ie, const char *abspath,
1663 int dirfd, const char *de_name, struct got_blob_object *blob)
1665 const struct got_error *err = NULL;
1666 char target_path[PATH_MAX];
1667 char etarget[PATH_MAX];
1668 ssize_t elen;
1669 size_t len, target_len = 0;
1670 const uint8_t *buf = got_object_blob_get_read_buf(blob);
1671 size_t hdrlen = got_object_blob_get_hdrlen(blob);
1673 *status = GOT_STATUS_NO_CHANGE;
1675 /* Blob object content specifies the target path of the link. */
1676 do {
1677 err = got_object_blob_read_block(&len, blob);
1678 if (err)
1679 return err;
1680 if (len + target_len >= sizeof(target_path)) {
1682 * Should not happen. The blob contents were OK
1683 * when this symlink was installed.
1685 return got_error(GOT_ERR_NO_SPACE);
1687 if (len > 0) {
1688 /* Skip blob object header first time around. */
1689 memcpy(target_path + target_len, buf + hdrlen,
1690 len - hdrlen);
1691 target_len += len - hdrlen;
1692 hdrlen = 0;
1694 } while (len != 0);
1695 target_path[target_len] = '\0';
1697 if (dirfd != -1) {
1698 elen = readlinkat(dirfd, de_name, etarget, sizeof(etarget));
1699 if (elen == -1)
1700 return got_error_from_errno2("readlinkat", abspath);
1701 } else {
1702 elen = readlink(abspath, etarget, sizeof(etarget));
1703 if (elen == -1)
1704 return got_error_from_errno2("readlink", abspath);
1707 if (elen != target_len || memcmp(etarget, target_path, target_len) != 0)
1708 *status = GOT_STATUS_MODIFY;
1710 return NULL;
1713 static const struct got_error *
1714 get_file_status(unsigned char *status, struct stat *sb,
1715 struct got_fileindex_entry *ie, const char *abspath,
1716 int dirfd, const char *de_name, struct got_repository *repo)
1718 const struct got_error *err = NULL;
1719 struct got_object_id id;
1720 size_t hdrlen;
1721 int fd = -1;
1722 FILE *f = NULL;
1723 uint8_t fbuf[8192];
1724 struct got_blob_object *blob = NULL;
1725 size_t flen, blen;
1726 unsigned char staged_status = get_staged_status(ie);
1728 *status = GOT_STATUS_NO_CHANGE;
1731 * Whenever the caller provides a directory descriptor and a
1732 * directory entry name for the file, use them! This prevents
1733 * race conditions if filesystem paths change beneath our feet.
1735 if (dirfd != -1) {
1736 if (fstatat(dirfd, de_name, sb, AT_SYMLINK_NOFOLLOW) == -1) {
1737 if (errno == ENOENT) {
1738 if (got_fileindex_entry_has_file_on_disk(ie))
1739 *status = GOT_STATUS_MISSING;
1740 else
1741 *status = GOT_STATUS_DELETE;
1742 goto done;
1744 err = got_error_from_errno2("fstatat", abspath);
1745 goto done;
1747 } else {
1748 fd = open(abspath, O_RDONLY | O_NOFOLLOW);
1749 if (fd == -1 && errno != ENOENT && errno != ELOOP)
1750 return got_error_from_errno2("open", abspath);
1751 else if (fd == -1 && errno == ELOOP) {
1752 if (lstat(abspath, sb) == -1)
1753 return got_error_from_errno2("lstat", abspath);
1754 } else if (fd == -1 || fstat(fd, sb) == -1) {
1755 if (errno == ENOENT) {
1756 if (got_fileindex_entry_has_file_on_disk(ie))
1757 *status = GOT_STATUS_MISSING;
1758 else
1759 *status = GOT_STATUS_DELETE;
1760 goto done;
1762 err = got_error_from_errno2("fstat", abspath);
1763 goto done;
1767 if (!S_ISREG(sb->st_mode) && !S_ISLNK(sb->st_mode)) {
1768 *status = GOT_STATUS_OBSTRUCTED;
1769 goto done;
1772 if (!got_fileindex_entry_has_file_on_disk(ie)) {
1773 *status = GOT_STATUS_DELETE;
1774 goto done;
1775 } else if (!got_fileindex_entry_has_blob(ie) &&
1776 staged_status != GOT_STATUS_ADD) {
1777 *status = GOT_STATUS_ADD;
1778 goto done;
1781 if (!stat_info_differs(ie, sb))
1782 goto done;
1784 if (S_ISLNK(sb->st_mode) &&
1785 got_fileindex_entry_filetype_get(ie) != GOT_FILEIDX_MODE_SYMLINK) {
1786 *status = GOT_STATUS_MODIFY;
1787 goto done;
1790 if (staged_status == GOT_STATUS_MODIFY ||
1791 staged_status == GOT_STATUS_ADD)
1792 memcpy(id.sha1, ie->staged_blob_sha1, sizeof(id.sha1));
1793 else
1794 memcpy(id.sha1, ie->blob_sha1, sizeof(id.sha1));
1796 err = got_object_open_as_blob(&blob, repo, &id, sizeof(fbuf));
1797 if (err)
1798 goto done;
1800 if (S_ISLNK(sb->st_mode)) {
1801 err = get_symlink_modification_status(status, ie,
1802 abspath, dirfd, de_name, blob);
1803 goto done;
1806 if (dirfd != -1) {
1807 fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW);
1808 if (fd == -1) {
1809 err = got_error_from_errno2("openat", abspath);
1810 goto done;
1814 f = fdopen(fd, "r");
1815 if (f == NULL) {
1816 err = got_error_from_errno2("fdopen", abspath);
1817 goto done;
1819 fd = -1;
1820 hdrlen = got_object_blob_get_hdrlen(blob);
1821 for (;;) {
1822 const uint8_t *bbuf = got_object_blob_get_read_buf(blob);
1823 err = got_object_blob_read_block(&blen, blob);
1824 if (err)
1825 goto done;
1826 /* Skip length of blob object header first time around. */
1827 flen = fread(fbuf, 1, sizeof(fbuf) - hdrlen, f);
1828 if (flen == 0 && ferror(f)) {
1829 err = got_error_from_errno("fread");
1830 goto done;
1832 if (blen - hdrlen == 0) {
1833 if (flen != 0)
1834 *status = GOT_STATUS_MODIFY;
1835 break;
1836 } else if (flen == 0) {
1837 if (blen - hdrlen != 0)
1838 *status = GOT_STATUS_MODIFY;
1839 break;
1840 } else if (blen - hdrlen == flen) {
1841 /* Skip blob object header first time around. */
1842 if (memcmp(bbuf + hdrlen, fbuf, flen) != 0) {
1843 *status = GOT_STATUS_MODIFY;
1844 break;
1846 } else {
1847 *status = GOT_STATUS_MODIFY;
1848 break;
1850 hdrlen = 0;
1853 if (*status == GOT_STATUS_MODIFY) {
1854 rewind(f);
1855 err = get_modified_file_content_status(status, f);
1856 } else if (xbit_differs(ie, sb->st_mode))
1857 *status = GOT_STATUS_MODE_CHANGE;
1858 done:
1859 if (blob)
1860 got_object_blob_close(blob);
1861 if (f != NULL && fclose(f) == EOF && err == NULL)
1862 err = got_error_from_errno2("fclose", abspath);
1863 if (fd != -1 && close(fd) == -1 && err == NULL)
1864 err = got_error_from_errno2("close", abspath);
1865 return err;
1869 * Update timestamps in the file index if a file is unmodified and
1870 * we had to run a full content comparison to find out.
1872 static const struct got_error *
1873 sync_timestamps(int wt_fd, const char *path, unsigned char status,
1874 struct got_fileindex_entry *ie, struct stat *sb)
1876 if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb))
1877 return got_fileindex_entry_update(ie, wt_fd, path,
1878 ie->blob_sha1, ie->commit_sha1, 1);
1880 return NULL;
1883 static const struct got_error *
1884 update_blob(struct got_worktree *worktree,
1885 struct got_fileindex *fileindex, struct got_fileindex_entry *ie,
1886 struct got_tree_entry *te, const char *path,
1887 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
1888 void *progress_arg)
1890 const struct got_error *err = NULL;
1891 struct got_blob_object *blob = NULL;
1892 char *ondisk_path;
1893 unsigned char status = GOT_STATUS_NO_CHANGE;
1894 struct stat sb;
1896 if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, path) == -1)
1897 return got_error_from_errno("asprintf");
1899 if (ie) {
1900 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE) {
1901 err = got_error_path(ie->path, GOT_ERR_FILE_STAGED);
1902 goto done;
1904 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
1905 repo);
1906 if (err)
1907 goto done;
1908 if (status == GOT_STATUS_MISSING || status == GOT_STATUS_DELETE)
1909 sb.st_mode = got_fileindex_perms_to_st(ie);
1910 } else {
1911 sb.st_mode = GOT_DEFAULT_FILE_MODE;
1912 status = GOT_STATUS_UNVERSIONED;
1915 if (status == GOT_STATUS_OBSTRUCTED) {
1916 err = (*progress_cb)(progress_arg, status, path);
1917 goto done;
1919 if (status == GOT_STATUS_CONFLICT) {
1920 err = (*progress_cb)(progress_arg, GOT_STATUS_CANNOT_UPDATE,
1921 path);
1922 goto done;
1925 if (ie && status != GOT_STATUS_MISSING &&
1926 (te->mode & S_IXUSR) == (sb.st_mode & S_IXUSR)) {
1927 if (got_fileindex_entry_has_commit(ie) &&
1928 memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
1929 SHA1_DIGEST_LENGTH) == 0) {
1930 err = sync_timestamps(worktree->root_fd,
1931 path, status, ie, &sb);
1932 if (err)
1933 goto done;
1934 err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
1935 path);
1936 goto done;
1938 if (got_fileindex_entry_has_blob(ie) &&
1939 memcmp(ie->blob_sha1, te->id.sha1,
1940 SHA1_DIGEST_LENGTH) == 0) {
1941 err = sync_timestamps(worktree->root_fd,
1942 path, status, ie, &sb);
1943 goto done;
1947 err = got_object_open_as_blob(&blob, repo, &te->id, 8192);
1948 if (err)
1949 goto done;
1951 if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_ADD) {
1952 int update_timestamps;
1953 struct got_blob_object *blob2 = NULL;
1954 char *label_orig = NULL;
1955 if (got_fileindex_entry_has_blob(ie)) {
1956 struct got_object_id id2;
1957 memcpy(id2.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
1958 err = got_object_open_as_blob(&blob2, repo, &id2, 8192);
1959 if (err)
1960 goto done;
1962 if (got_fileindex_entry_has_commit(ie)) {
1963 char id_str[SHA1_DIGEST_STRING_LENGTH];
1964 if (got_sha1_digest_to_str(ie->commit_sha1, id_str,
1965 sizeof(id_str)) == NULL) {
1966 err = got_error_path(id_str,
1967 GOT_ERR_BAD_OBJ_ID_STR);
1968 goto done;
1970 if (asprintf(&label_orig, "%s: commit %s",
1971 GOT_MERGE_LABEL_BASE, id_str) == -1) {
1972 err = got_error_from_errno("asprintf");
1973 goto done;
1976 if (S_ISLNK(te->mode) && S_ISLNK(sb.st_mode)) {
1977 char *link_target;
1978 err = got_object_blob_read_to_str(&link_target, blob);
1979 if (err)
1980 goto done;
1981 err = merge_symlink(worktree, blob2, ondisk_path, path,
1982 label_orig, link_target, worktree->base_commit_id,
1983 repo, progress_cb, progress_arg);
1984 free(link_target);
1985 } else {
1986 err = merge_blob(&update_timestamps, worktree, blob2,
1987 ondisk_path, path, sb.st_mode, label_orig, blob,
1988 worktree->base_commit_id, repo,
1989 progress_cb, progress_arg);
1991 free(label_orig);
1992 if (blob2)
1993 got_object_blob_close(blob2);
1994 if (err)
1995 goto done;
1997 * Do not update timestamps of files with local changes.
1998 * Otherwise, a future status walk would treat them as
1999 * unmodified files again.
2001 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2002 blob->id.sha1, worktree->base_commit_id->sha1,
2003 update_timestamps);
2004 } else if (status == GOT_STATUS_MODE_CHANGE) {
2005 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2006 blob->id.sha1, worktree->base_commit_id->sha1, 0);
2007 } else if (status == GOT_STATUS_DELETE) {
2008 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
2009 if (err)
2010 goto done;
2011 err = got_fileindex_entry_update(ie, worktree->root_fd, path,
2012 blob->id.sha1, worktree->base_commit_id->sha1, 0);
2013 if (err)
2014 goto done;
2015 } else {
2016 int is_bad_symlink = 0;
2017 if (S_ISLNK(te->mode)) {
2018 err = install_symlink(&is_bad_symlink, worktree,
2019 ondisk_path, path, blob,
2020 status == GOT_STATUS_MISSING, 0,
2021 status == GOT_STATUS_UNVERSIONED, repo,
2022 progress_cb, progress_arg);
2023 } else {
2024 err = install_blob(worktree, ondisk_path, path,
2025 te->mode, sb.st_mode, blob,
2026 status == GOT_STATUS_MISSING, 0, 0,
2027 status == GOT_STATUS_UNVERSIONED, repo,
2028 progress_cb, progress_arg);
2030 if (err)
2031 goto done;
2033 if (ie) {
2034 err = got_fileindex_entry_update(ie,
2035 worktree->root_fd, path, blob->id.sha1,
2036 worktree->base_commit_id->sha1, 1);
2037 } else {
2038 err = create_fileindex_entry(&ie, fileindex,
2039 worktree->base_commit_id, worktree->root_fd, path,
2040 &blob->id);
2042 if (err)
2043 goto done;
2045 if (is_bad_symlink) {
2046 got_fileindex_entry_filetype_set(ie,
2047 GOT_FILEIDX_MODE_BAD_SYMLINK);
2050 got_object_blob_close(blob);
2051 done:
2052 free(ondisk_path);
2053 return err;
2056 static const struct got_error *
2057 remove_ondisk_file(const char *root_path, const char *path)
2059 const struct got_error *err = NULL;
2060 char *ondisk_path = NULL;
2062 if (asprintf(&ondisk_path, "%s/%s", root_path, path) == -1)
2063 return got_error_from_errno("asprintf");
2065 if (unlink(ondisk_path) == -1) {
2066 if (errno != ENOENT)
2067 err = got_error_from_errno2("unlink", ondisk_path);
2068 } else {
2069 size_t root_len = strlen(root_path);
2070 do {
2071 char *parent;
2072 err = got_path_dirname(&parent, ondisk_path);
2073 if (err)
2074 break;
2075 free(ondisk_path);
2076 ondisk_path = parent;
2077 if (rmdir(ondisk_path) == -1) {
2078 if (errno != ENOTEMPTY)
2079 err = got_error_from_errno2("rmdir",
2080 ondisk_path);
2081 break;
2083 } while (got_path_cmp(ondisk_path, root_path,
2084 strlen(ondisk_path), root_len) != 0);
2086 free(ondisk_path);
2087 return err;
2090 static const struct got_error *
2091 delete_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
2092 struct got_fileindex_entry *ie, struct got_repository *repo,
2093 got_worktree_checkout_cb progress_cb, void *progress_arg)
2095 const struct got_error *err = NULL;
2096 unsigned char status;
2097 struct stat sb;
2098 char *ondisk_path;
2100 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE)
2101 return got_error_path(ie->path, GOT_ERR_FILE_STAGED);
2103 if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, ie->path)
2104 == -1)
2105 return got_error_from_errno("asprintf");
2107 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo);
2108 if (err)
2109 goto done;
2111 if (S_ISLNK(sb.st_mode) && status != GOT_STATUS_NO_CHANGE) {
2112 char ondisk_target[PATH_MAX];
2113 ssize_t ondisk_len = readlink(ondisk_path, ondisk_target,
2114 sizeof(ondisk_target));
2115 if (ondisk_len == -1) {
2116 err = got_error_from_errno2("readlink", ondisk_path);
2117 goto done;
2119 ondisk_target[ondisk_len] = '\0';
2120 err = install_symlink_conflict(NULL, worktree->base_commit_id,
2121 NULL, NULL, /* XXX pass common ancestor info? */
2122 ondisk_target, ondisk_path);
2123 if (err)
2124 goto done;
2125 err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT,
2126 ie->path);
2127 goto done;
2130 if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_CONFLICT ||
2131 status == GOT_STATUS_ADD) {
2132 err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, ie->path);
2133 if (err)
2134 goto done;
2136 * Preserve the working file and change the deleted blob's
2137 * entry into a schedule-add entry.
2139 err = got_fileindex_entry_update(ie, worktree->root_fd,
2140 ie->path, NULL, NULL, 0);
2141 } else {
2142 err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE, ie->path);
2143 if (err)
2144 goto done;
2145 if (status == GOT_STATUS_NO_CHANGE) {
2146 err = remove_ondisk_file(worktree->root_path, ie->path);
2147 if (err)
2148 goto done;
2150 got_fileindex_entry_remove(fileindex, ie);
2152 done:
2153 free(ondisk_path);
2154 return err;
2157 struct diff_cb_arg {
2158 struct got_fileindex *fileindex;
2159 struct got_worktree *worktree;
2160 struct got_repository *repo;
2161 got_worktree_checkout_cb progress_cb;
2162 void *progress_arg;
2163 got_cancel_cb cancel_cb;
2164 void *cancel_arg;
2167 static const struct got_error *
2168 diff_old_new(void *arg, struct got_fileindex_entry *ie,
2169 struct got_tree_entry *te, const char *parent_path)
2171 struct diff_cb_arg *a = arg;
2173 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
2174 return got_error(GOT_ERR_CANCELLED);
2176 return update_blob(a->worktree, a->fileindex, ie, te,
2177 ie->path, a->repo, a->progress_cb, a->progress_arg);
2180 static const struct got_error *
2181 diff_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path)
2183 struct diff_cb_arg *a = arg;
2185 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
2186 return got_error(GOT_ERR_CANCELLED);
2188 return delete_blob(a->worktree, a->fileindex, ie,
2189 a->repo, a->progress_cb, a->progress_arg);
2192 static const struct got_error *
2193 diff_new(void *arg, struct got_tree_entry *te, const char *parent_path)
2195 struct diff_cb_arg *a = arg;
2196 const struct got_error *err;
2197 char *path;
2199 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
2200 return got_error(GOT_ERR_CANCELLED);
2202 if (got_object_tree_entry_is_submodule(te))
2203 return NULL;
2205 if (asprintf(&path, "%s%s%s", parent_path,
2206 parent_path[0] ? "/" : "", te->name)
2207 == -1)
2208 return got_error_from_errno("asprintf");
2210 if (S_ISDIR(te->mode))
2211 err = add_dir_on_disk(a->worktree, path);
2212 else
2213 err = update_blob(a->worktree, a->fileindex, NULL, te, path,
2214 a->repo, a->progress_cb, a->progress_arg);
2216 free(path);
2217 return err;
2220 const struct got_error *
2221 got_worktree_get_uuid(char **uuidstr, struct got_worktree *worktree)
2223 uint32_t uuid_status;
2225 uuid_to_string(&worktree->uuid, uuidstr, &uuid_status);
2226 if (uuid_status != uuid_s_ok) {
2227 *uuidstr = NULL;
2228 return got_error_uuid(uuid_status, "uuid_to_string");
2231 return NULL;
2234 static const struct got_error *
2235 get_ref_name(char **refname, struct got_worktree *worktree, const char *prefix)
2237 const struct got_error *err = NULL;
2238 char *uuidstr = NULL;
2240 *refname = NULL;
2242 err = got_worktree_get_uuid(&uuidstr, worktree);
2243 if (err)
2244 return err;
2246 if (asprintf(refname, "%s-%s", prefix, uuidstr) == -1) {
2247 err = got_error_from_errno("asprintf");
2248 *refname = NULL;
2250 free(uuidstr);
2251 return err;
2254 const struct got_error *
2255 got_worktree_get_base_ref_name(char **refname, struct got_worktree *worktree)
2257 return get_ref_name(refname, worktree, GOT_WORKTREE_BASE_REF_PREFIX);
2260 static const struct got_error *
2261 get_rebase_tmp_ref_name(char **refname, struct got_worktree *worktree)
2263 return get_ref_name(refname, worktree,
2264 GOT_WORKTREE_REBASE_TMP_REF_PREFIX);
2267 static const struct got_error *
2268 get_newbase_symref_name(char **refname, struct got_worktree *worktree)
2270 return get_ref_name(refname, worktree, GOT_WORKTREE_NEWBASE_REF_PREFIX);
2273 static const struct got_error *
2274 get_rebase_branch_symref_name(char **refname, struct got_worktree *worktree)
2276 return get_ref_name(refname, worktree,
2277 GOT_WORKTREE_REBASE_BRANCH_REF_PREFIX);
2280 static const struct got_error *
2281 get_rebase_commit_ref_name(char **refname, struct got_worktree *worktree)
2283 return get_ref_name(refname, worktree,
2284 GOT_WORKTREE_REBASE_COMMIT_REF_PREFIX);
2287 static const struct got_error *
2288 get_histedit_tmp_ref_name(char **refname, struct got_worktree *worktree)
2290 return get_ref_name(refname, worktree,
2291 GOT_WORKTREE_HISTEDIT_TMP_REF_PREFIX);
2294 static const struct got_error *
2295 get_histedit_branch_symref_name(char **refname, struct got_worktree *worktree)
2297 return get_ref_name(refname, worktree,
2298 GOT_WORKTREE_HISTEDIT_BRANCH_REF_PREFIX);
2301 static const struct got_error *
2302 get_histedit_base_commit_ref_name(char **refname, struct got_worktree *worktree)
2304 return get_ref_name(refname, worktree,
2305 GOT_WORKTREE_HISTEDIT_BASE_COMMIT_REF_PREFIX);
2308 static const struct got_error *
2309 get_histedit_commit_ref_name(char **refname, struct got_worktree *worktree)
2311 return get_ref_name(refname, worktree,
2312 GOT_WORKTREE_HISTEDIT_COMMIT_REF_PREFIX);
2315 const struct got_error *
2316 got_worktree_get_histedit_script_path(char **path,
2317 struct got_worktree *worktree)
2319 if (asprintf(path, "%s/%s/%s", worktree->root_path,
2320 GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_HISTEDIT_SCRIPT) == -1) {
2321 *path = NULL;
2322 return got_error_from_errno("asprintf");
2324 return NULL;
2328 * Prevent Git's garbage collector from deleting our base commit by
2329 * setting a reference to our base commit's ID.
2331 static const struct got_error *
2332 ref_base_commit(struct got_worktree *worktree, struct got_repository *repo)
2334 const struct got_error *err = NULL;
2335 struct got_reference *ref = NULL;
2336 char *refname;
2338 err = got_worktree_get_base_ref_name(&refname, worktree);
2339 if (err)
2340 return err;
2342 err = got_ref_alloc(&ref, refname, worktree->base_commit_id);
2343 if (err)
2344 goto done;
2346 err = got_ref_write(ref, repo);
2347 done:
2348 free(refname);
2349 if (ref)
2350 got_ref_close(ref);
2351 return err;
2354 static const struct got_error *
2355 get_fileindex_path(char **fileindex_path, struct got_worktree *worktree)
2357 const struct got_error *err = NULL;
2359 if (asprintf(fileindex_path, "%s/%s/%s", worktree->root_path,
2360 GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_FILE_INDEX) == -1) {
2361 err = got_error_from_errno("asprintf");
2362 *fileindex_path = NULL;
2364 return err;
2368 static const struct got_error *
2369 open_fileindex(struct got_fileindex **fileindex, char **fileindex_path,
2370 struct got_worktree *worktree)
2372 const struct got_error *err = NULL;
2373 FILE *index = NULL;
2375 *fileindex_path = NULL;
2376 *fileindex = got_fileindex_alloc();
2377 if (*fileindex == NULL)
2378 return got_error_from_errno("got_fileindex_alloc");
2380 err = get_fileindex_path(fileindex_path, worktree);
2381 if (err)
2382 goto done;
2384 index = fopen(*fileindex_path, "rb");
2385 if (index == NULL) {
2386 if (errno != ENOENT)
2387 err = got_error_from_errno2("fopen", *fileindex_path);
2388 } else {
2389 err = got_fileindex_read(*fileindex, index);
2390 if (fclose(index) != 0 && err == NULL)
2391 err = got_error_from_errno("fclose");
2393 done:
2394 if (err) {
2395 free(*fileindex_path);
2396 *fileindex_path = NULL;
2397 got_fileindex_free(*fileindex);
2398 *fileindex = NULL;
2400 return err;
2403 struct bump_base_commit_id_arg {
2404 struct got_object_id *base_commit_id;
2405 const char *path;
2406 size_t path_len;
2407 const char *entry_name;
2408 got_worktree_checkout_cb progress_cb;
2409 void *progress_arg;
2412 /* Bump base commit ID of all files within an updated part of the work tree. */
2413 static const struct got_error *
2414 bump_base_commit_id(void *arg, struct got_fileindex_entry *ie)
2416 const struct got_error *err;
2417 struct bump_base_commit_id_arg *a = arg;
2419 if (a->entry_name) {
2420 if (strcmp(ie->path, a->path) != 0)
2421 return NULL;
2422 } else if (!got_path_is_child(ie->path, a->path, a->path_len))
2423 return NULL;
2425 if (memcmp(ie->commit_sha1, a->base_commit_id->sha1,
2426 SHA1_DIGEST_LENGTH) == 0)
2427 return NULL;
2429 if (a->progress_cb) {
2430 err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_BUMP_BASE,
2431 ie->path);
2432 if (err)
2433 return err;
2435 memcpy(ie->commit_sha1, a->base_commit_id->sha1, SHA1_DIGEST_LENGTH);
2436 return NULL;
2439 static const struct got_error *
2440 sync_fileindex(struct got_fileindex *fileindex, const char *fileindex_path)
2442 const struct got_error *err = NULL;
2443 char *new_fileindex_path = NULL;
2444 FILE *new_index = NULL;
2445 struct timespec timeout;
2447 err = got_opentemp_named(&new_fileindex_path, &new_index,
2448 fileindex_path);
2449 if (err)
2450 goto done;
2452 err = got_fileindex_write(fileindex, new_index);
2453 if (err)
2454 goto done;
2456 if (rename(new_fileindex_path, fileindex_path) != 0) {
2457 err = got_error_from_errno3("rename", new_fileindex_path,
2458 fileindex_path);
2459 unlink(new_fileindex_path);
2463 * Sleep for a short amount of time to ensure that files modified after
2464 * this program exits have a different time stamp from the one which
2465 * was recorded in the file index.
2467 timeout.tv_sec = 0;
2468 timeout.tv_nsec = 1;
2469 nanosleep(&timeout, NULL);
2470 done:
2471 if (new_index)
2472 fclose(new_index);
2473 free(new_fileindex_path);
2474 return err;
2477 static const struct got_error *
2478 find_tree_entry_for_checkout(int *entry_type, char **tree_relpath,
2479 struct got_object_id **tree_id, const char *wt_relpath,
2480 struct got_worktree *worktree, struct got_repository *repo)
2482 const struct got_error *err = NULL;
2483 struct got_object_id *id = NULL;
2484 char *in_repo_path = NULL;
2485 int is_root_wt = got_path_is_root_dir(worktree->path_prefix);
2487 *entry_type = GOT_OBJ_TYPE_ANY;
2488 *tree_relpath = NULL;
2489 *tree_id = NULL;
2491 if (wt_relpath[0] == '\0') {
2492 /* Check out all files within the work tree. */
2493 *entry_type = GOT_OBJ_TYPE_TREE;
2494 *tree_relpath = strdup("");
2495 if (*tree_relpath == NULL) {
2496 err = got_error_from_errno("strdup");
2497 goto done;
2499 err = got_object_id_by_path(tree_id, repo,
2500 worktree->base_commit_id, worktree->path_prefix);
2501 if (err)
2502 goto done;
2503 return NULL;
2506 /* Check out a subset of files in the work tree. */
2508 if (asprintf(&in_repo_path, "%s%s%s", worktree->path_prefix,
2509 is_root_wt ? "" : "/", wt_relpath) == -1) {
2510 err = got_error_from_errno("asprintf");
2511 goto done;
2514 err = got_object_id_by_path(&id, repo, worktree->base_commit_id,
2515 in_repo_path);
2516 if (err)
2517 goto done;
2519 free(in_repo_path);
2520 in_repo_path = NULL;
2522 err = got_object_get_type(entry_type, repo, id);
2523 if (err)
2524 goto done;
2526 if (*entry_type == GOT_OBJ_TYPE_BLOB) {
2527 /* Check out a single file. */
2528 if (strchr(wt_relpath, '/') == NULL) {
2529 /* Check out a single file in work tree's root dir. */
2530 in_repo_path = strdup(worktree->path_prefix);
2531 if (in_repo_path == NULL) {
2532 err = got_error_from_errno("strdup");
2533 goto done;
2535 *tree_relpath = strdup("");
2536 if (*tree_relpath == NULL) {
2537 err = got_error_from_errno("strdup");
2538 goto done;
2540 } else {
2541 /* Check out a single file in a subdirectory. */
2542 err = got_path_dirname(tree_relpath, wt_relpath);
2543 if (err)
2544 return err;
2545 if (asprintf(&in_repo_path, "%s%s%s",
2546 worktree->path_prefix, is_root_wt ? "" : "/",
2547 *tree_relpath) == -1) {
2548 err = got_error_from_errno("asprintf");
2549 goto done;
2552 err = got_object_id_by_path(tree_id, repo,
2553 worktree->base_commit_id, in_repo_path);
2554 } else {
2555 /* Check out all files within a subdirectory. */
2556 *tree_id = got_object_id_dup(id);
2557 if (*tree_id == NULL) {
2558 err = got_error_from_errno("got_object_id_dup");
2559 goto done;
2561 *tree_relpath = strdup(wt_relpath);
2562 if (*tree_relpath == NULL) {
2563 err = got_error_from_errno("strdup");
2564 goto done;
2567 done:
2568 free(id);
2569 free(in_repo_path);
2570 if (err) {
2571 *entry_type = GOT_OBJ_TYPE_ANY;
2572 free(*tree_relpath);
2573 *tree_relpath = NULL;
2574 free(*tree_id);
2575 *tree_id = NULL;
2577 return err;
2580 static const struct got_error *
2581 checkout_files(struct got_worktree *worktree, struct got_fileindex *fileindex,
2582 const char *relpath, struct got_object_id *tree_id, const char *entry_name,
2583 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
2584 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
2586 const struct got_error *err = NULL;
2587 struct got_commit_object *commit = NULL;
2588 struct got_tree_object *tree = NULL;
2589 struct got_fileindex_diff_tree_cb diff_cb;
2590 struct diff_cb_arg arg;
2592 err = ref_base_commit(worktree, repo);
2593 if (err) {
2594 if (!(err->code == GOT_ERR_ERRNO &&
2595 (errno == EACCES || errno == EROFS)))
2596 goto done;
2597 err = (*progress_cb)(progress_arg,
2598 GOT_STATUS_BASE_REF_ERR, worktree->root_path);
2599 if (err)
2600 return err;
2603 err = got_object_open_as_commit(&commit, repo,
2604 worktree->base_commit_id);
2605 if (err)
2606 goto done;
2608 err = got_object_open_as_tree(&tree, repo, tree_id);
2609 if (err)
2610 goto done;
2612 if (entry_name &&
2613 got_object_tree_find_entry(tree, entry_name) == NULL) {
2614 err = got_error_path(entry_name, GOT_ERR_NO_TREE_ENTRY);
2615 goto done;
2618 diff_cb.diff_old_new = diff_old_new;
2619 diff_cb.diff_old = diff_old;
2620 diff_cb.diff_new = diff_new;
2621 arg.fileindex = fileindex;
2622 arg.worktree = worktree;
2623 arg.repo = repo;
2624 arg.progress_cb = progress_cb;
2625 arg.progress_arg = progress_arg;
2626 arg.cancel_cb = cancel_cb;
2627 arg.cancel_arg = cancel_arg;
2628 err = got_fileindex_diff_tree(fileindex, tree, relpath,
2629 entry_name, repo, &diff_cb, &arg);
2630 done:
2631 if (tree)
2632 got_object_tree_close(tree);
2633 if (commit)
2634 got_object_commit_close(commit);
2635 return err;
2638 const struct got_error *
2639 got_worktree_checkout_files(struct got_worktree *worktree,
2640 struct got_pathlist_head *paths, struct got_repository *repo,
2641 got_worktree_checkout_cb progress_cb, void *progress_arg,
2642 got_cancel_cb cancel_cb, void *cancel_arg)
2644 const struct got_error *err = NULL, *sync_err, *unlockerr;
2645 struct got_commit_object *commit = NULL;
2646 struct got_tree_object *tree = NULL;
2647 struct got_fileindex *fileindex = NULL;
2648 char *fileindex_path = NULL;
2649 struct got_pathlist_entry *pe;
2650 struct tree_path_data {
2651 SIMPLEQ_ENTRY(tree_path_data) entry;
2652 struct got_object_id *tree_id;
2653 int entry_type;
2654 char *relpath;
2655 char *entry_name;
2656 } *tpd = NULL;
2657 SIMPLEQ_HEAD(tree_paths, tree_path_data) tree_paths;
2659 SIMPLEQ_INIT(&tree_paths);
2661 err = lock_worktree(worktree, LOCK_EX);
2662 if (err)
2663 return err;
2665 /* Map all specified paths to in-repository trees. */
2666 TAILQ_FOREACH(pe, paths, entry) {
2667 tpd = malloc(sizeof(*tpd));
2668 if (tpd == NULL) {
2669 err = got_error_from_errno("malloc");
2670 goto done;
2673 err = find_tree_entry_for_checkout(&tpd->entry_type,
2674 &tpd->relpath, &tpd->tree_id, pe->path, worktree, repo);
2675 if (err) {
2676 free(tpd);
2677 goto done;
2680 if (tpd->entry_type == GOT_OBJ_TYPE_BLOB) {
2681 err = got_path_basename(&tpd->entry_name, pe->path);
2682 if (err) {
2683 free(tpd->relpath);
2684 free(tpd->tree_id);
2685 free(tpd);
2686 goto done;
2688 } else
2689 tpd->entry_name = NULL;
2691 SIMPLEQ_INSERT_TAIL(&tree_paths, tpd, entry);
2695 * Read the file index.
2696 * Checking out files is supposed to be an idempotent operation.
2697 * If the on-disk file index is incomplete we will try to complete it.
2699 err = open_fileindex(&fileindex, &fileindex_path, worktree);
2700 if (err)
2701 goto done;
2703 tpd = SIMPLEQ_FIRST(&tree_paths);
2704 TAILQ_FOREACH(pe, paths, entry) {
2705 struct bump_base_commit_id_arg bbc_arg;
2707 err = checkout_files(worktree, fileindex, tpd->relpath,
2708 tpd->tree_id, tpd->entry_name, repo,
2709 progress_cb, progress_arg, cancel_cb, cancel_arg);
2710 if (err)
2711 break;
2713 bbc_arg.base_commit_id = worktree->base_commit_id;
2714 bbc_arg.entry_name = tpd->entry_name;
2715 bbc_arg.path = pe->path;
2716 bbc_arg.path_len = pe->path_len;
2717 bbc_arg.progress_cb = progress_cb;
2718 bbc_arg.progress_arg = progress_arg;
2719 err = got_fileindex_for_each_entry_safe(fileindex,
2720 bump_base_commit_id, &bbc_arg);
2721 if (err)
2722 break;
2724 tpd = SIMPLEQ_NEXT(tpd, entry);
2726 sync_err = sync_fileindex(fileindex, fileindex_path);
2727 if (sync_err && err == NULL)
2728 err = sync_err;
2729 done:
2730 free(fileindex_path);
2731 if (tree)
2732 got_object_tree_close(tree);
2733 if (commit)
2734 got_object_commit_close(commit);
2735 if (fileindex)
2736 got_fileindex_free(fileindex);
2737 while (!SIMPLEQ_EMPTY(&tree_paths)) {
2738 tpd = SIMPLEQ_FIRST(&tree_paths);
2739 SIMPLEQ_REMOVE_HEAD(&tree_paths, entry);
2740 free(tpd->relpath);
2741 free(tpd->tree_id);
2742 free(tpd);
2744 unlockerr = lock_worktree(worktree, LOCK_SH);
2745 if (unlockerr && err == NULL)
2746 err = unlockerr;
2747 return err;
2750 struct merge_file_cb_arg {
2751 struct got_worktree *worktree;
2752 struct got_fileindex *fileindex;
2753 got_worktree_checkout_cb progress_cb;
2754 void *progress_arg;
2755 got_cancel_cb cancel_cb;
2756 void *cancel_arg;
2757 const char *label_orig;
2758 struct got_object_id *commit_id2;
2761 static const struct got_error *
2762 merge_file_cb(void *arg, struct got_blob_object *blob1,
2763 struct got_blob_object *blob2, struct got_object_id *id1,
2764 struct got_object_id *id2, const char *path1, const char *path2,
2765 mode_t mode1, mode_t mode2, struct got_repository *repo)
2767 static const struct got_error *err = NULL;
2768 struct merge_file_cb_arg *a = arg;
2769 struct got_fileindex_entry *ie;
2770 char *ondisk_path = NULL;
2771 struct stat sb;
2772 unsigned char status;
2773 int local_changes_subsumed;
2775 if (blob1 && blob2) {
2776 ie = got_fileindex_entry_get(a->fileindex, path2,
2777 strlen(path2));
2778 if (ie == NULL)
2779 return (*a->progress_cb)(a->progress_arg,
2780 GOT_STATUS_MISSING, path2);
2782 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
2783 path2) == -1)
2784 return got_error_from_errno("asprintf");
2786 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
2787 repo);
2788 if (err)
2789 goto done;
2791 if (status == GOT_STATUS_DELETE) {
2792 err = (*a->progress_cb)(a->progress_arg,
2793 GOT_STATUS_MERGE, path2);
2794 goto done;
2796 if (status != GOT_STATUS_NO_CHANGE &&
2797 status != GOT_STATUS_MODIFY &&
2798 status != GOT_STATUS_CONFLICT &&
2799 status != GOT_STATUS_ADD) {
2800 err = (*a->progress_cb)(a->progress_arg, status, path2);
2801 goto done;
2804 if (S_ISLNK(mode1) && S_ISLNK(mode2)) {
2805 char *link_target2;
2806 err = got_object_blob_read_to_str(&link_target2, blob2);
2807 if (err)
2808 goto done;
2809 err = merge_symlink(a->worktree, blob1, ondisk_path,
2810 path2, a->label_orig, link_target2, a->commit_id2,
2811 repo, a->progress_cb, a->progress_arg);
2812 free(link_target2);
2813 } else {
2814 err = merge_blob(&local_changes_subsumed, a->worktree,
2815 blob1, ondisk_path, path2, sb.st_mode,
2816 a->label_orig, blob2, a->commit_id2, repo,
2817 a->progress_cb, a->progress_arg);
2819 } else if (blob1) {
2820 ie = got_fileindex_entry_get(a->fileindex, path1,
2821 strlen(path1));
2822 if (ie == NULL)
2823 return (*a->progress_cb)(a->progress_arg,
2824 GOT_STATUS_MISSING, path1);
2826 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
2827 path1) == -1)
2828 return got_error_from_errno("asprintf");
2830 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
2831 repo);
2832 if (err)
2833 goto done;
2835 switch (status) {
2836 case GOT_STATUS_NO_CHANGE:
2837 err = (*a->progress_cb)(a->progress_arg,
2838 GOT_STATUS_DELETE, path1);
2839 if (err)
2840 goto done;
2841 err = remove_ondisk_file(a->worktree->root_path, path1);
2842 if (err)
2843 goto done;
2844 if (ie)
2845 got_fileindex_entry_mark_deleted_from_disk(ie);
2846 break;
2847 case GOT_STATUS_DELETE:
2848 case GOT_STATUS_MISSING:
2849 err = (*a->progress_cb)(a->progress_arg,
2850 GOT_STATUS_DELETE, path1);
2851 if (err)
2852 goto done;
2853 if (ie)
2854 got_fileindex_entry_mark_deleted_from_disk(ie);
2855 break;
2856 case GOT_STATUS_ADD: {
2857 struct got_object_id *id;
2858 FILE *blob1_f;
2860 * Delete the added file only if its content already
2861 * exists in the repository.
2863 err = got_object_blob_file_create(&id, &blob1_f, path1);
2864 if (err)
2865 goto done;
2866 if (got_object_id_cmp(id, id1) == 0) {
2867 err = (*a->progress_cb)(a->progress_arg,
2868 GOT_STATUS_DELETE, path1);
2869 if (err)
2870 goto done;
2871 err = remove_ondisk_file(a->worktree->root_path,
2872 path1);
2873 if (err)
2874 goto done;
2875 if (ie)
2876 got_fileindex_entry_remove(a->fileindex,
2877 ie);
2878 } else {
2879 err = (*a->progress_cb)(a->progress_arg,
2880 GOT_STATUS_CANNOT_DELETE, path1);
2882 if (fclose(blob1_f) == EOF && err == NULL)
2883 err = got_error_from_errno("fclose");
2884 free(id);
2885 if (err)
2886 goto done;
2887 break;
2889 case GOT_STATUS_MODIFY:
2890 case GOT_STATUS_CONFLICT:
2891 err = (*a->progress_cb)(a->progress_arg,
2892 GOT_STATUS_CANNOT_DELETE, path1);
2893 if (err)
2894 goto done;
2895 break;
2896 case GOT_STATUS_OBSTRUCTED:
2897 err = (*a->progress_cb)(a->progress_arg, status, path1);
2898 if (err)
2899 goto done;
2900 break;
2901 default:
2902 break;
2904 } else if (blob2) {
2905 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
2906 path2) == -1)
2907 return got_error_from_errno("asprintf");
2908 ie = got_fileindex_entry_get(a->fileindex, path2,
2909 strlen(path2));
2910 if (ie) {
2911 err = get_file_status(&status, &sb, ie, ondisk_path,
2912 -1, NULL, repo);
2913 if (err)
2914 goto done;
2915 if (status != GOT_STATUS_NO_CHANGE &&
2916 status != GOT_STATUS_MODIFY &&
2917 status != GOT_STATUS_CONFLICT &&
2918 status != GOT_STATUS_ADD) {
2919 err = (*a->progress_cb)(a->progress_arg,
2920 status, path2);
2921 goto done;
2923 if (S_ISLNK(mode2) && S_ISLNK(sb.st_mode)) {
2924 char *link_target2;
2925 err = got_object_blob_read_to_str(&link_target2,
2926 blob2);
2927 if (err)
2928 goto done;
2929 err = merge_symlink(a->worktree, NULL,
2930 ondisk_path, path2, a->label_orig,
2931 link_target2, a->commit_id2, repo,
2932 a->progress_cb, a->progress_arg);
2933 free(link_target2);
2934 } else if (S_ISREG(sb.st_mode)) {
2935 err = merge_blob(&local_changes_subsumed,
2936 a->worktree, NULL, ondisk_path, path2,
2937 sb.st_mode, a->label_orig, blob2,
2938 a->commit_id2, repo, a->progress_cb,
2939 a->progress_arg);
2940 } else {
2941 err = got_error_path(ondisk_path,
2942 GOT_ERR_FILE_OBSTRUCTED);
2944 if (err)
2945 goto done;
2946 if (status == GOT_STATUS_DELETE) {
2947 err = got_fileindex_entry_update(ie,
2948 a->worktree->root_fd, path2, blob2->id.sha1,
2949 a->worktree->base_commit_id->sha1, 0);
2950 if (err)
2951 goto done;
2953 } else {
2954 int is_bad_symlink = 0;
2955 sb.st_mode = GOT_DEFAULT_FILE_MODE;
2956 if (S_ISLNK(mode2)) {
2957 err = install_symlink(&is_bad_symlink,
2958 a->worktree, ondisk_path, path2, blob2, 0,
2959 0, 1, repo, a->progress_cb, a->progress_arg);
2960 } else {
2961 err = install_blob(a->worktree, ondisk_path, path2,
2962 mode2, sb.st_mode, blob2, 0, 0, 0, 1, repo,
2963 a->progress_cb, a->progress_arg);
2965 if (err)
2966 goto done;
2967 err = got_fileindex_entry_alloc(&ie, path2);
2968 if (err)
2969 goto done;
2970 err = got_fileindex_entry_update(ie,
2971 a->worktree->root_fd, path2, NULL, NULL, 1);
2972 if (err) {
2973 got_fileindex_entry_free(ie);
2974 goto done;
2976 err = got_fileindex_entry_add(a->fileindex, ie);
2977 if (err) {
2978 got_fileindex_entry_free(ie);
2979 goto done;
2981 if (is_bad_symlink) {
2982 got_fileindex_entry_filetype_set(ie,
2983 GOT_FILEIDX_MODE_BAD_SYMLINK);
2987 done:
2988 free(ondisk_path);
2989 return err;
2992 struct check_merge_ok_arg {
2993 struct got_worktree *worktree;
2994 struct got_repository *repo;
2997 static const struct got_error *
2998 check_merge_ok(void *arg, struct got_fileindex_entry *ie)
3000 const struct got_error *err = NULL;
3001 struct check_merge_ok_arg *a = arg;
3002 unsigned char status;
3003 struct stat sb;
3004 char *ondisk_path;
3006 /* Reject merges into a work tree with mixed base commits. */
3007 if (memcmp(ie->commit_sha1, a->worktree->base_commit_id->sha1,
3008 SHA1_DIGEST_LENGTH))
3009 return got_error(GOT_ERR_MIXED_COMMITS);
3011 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path)
3012 == -1)
3013 return got_error_from_errno("asprintf");
3015 /* Reject merges into a work tree with conflicted files. */
3016 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
3017 if (err)
3018 return err;
3019 if (status == GOT_STATUS_CONFLICT)
3020 return got_error(GOT_ERR_CONFLICTS);
3022 return NULL;
3025 static const struct got_error *
3026 merge_files(struct got_worktree *worktree, struct got_fileindex *fileindex,
3027 const char *fileindex_path, struct got_object_id *commit_id1,
3028 struct got_object_id *commit_id2, struct got_repository *repo,
3029 got_worktree_checkout_cb progress_cb, void *progress_arg,
3030 got_cancel_cb cancel_cb, void *cancel_arg)
3032 const struct got_error *err = NULL, *sync_err;
3033 struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
3034 struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3035 struct merge_file_cb_arg arg;
3036 char *label_orig = NULL;
3038 if (commit_id1) {
3039 err = got_object_id_by_path(&tree_id1, repo, commit_id1,
3040 worktree->path_prefix);
3041 if (err && err->code != GOT_ERR_NO_TREE_ENTRY)
3042 goto done;
3044 if (tree_id1) {
3045 char *id_str;
3047 err = got_object_open_as_tree(&tree1, repo, tree_id1);
3048 if (err)
3049 goto done;
3051 err = got_object_id_str(&id_str, commit_id1);
3052 if (err)
3053 goto done;
3055 if (asprintf(&label_orig, "%s: commit %s",
3056 GOT_MERGE_LABEL_BASE, id_str) == -1) {
3057 err = got_error_from_errno("asprintf");
3058 free(id_str);
3059 goto done;
3061 free(id_str);
3064 err = got_object_id_by_path(&tree_id2, repo, commit_id2,
3065 worktree->path_prefix);
3066 if (err)
3067 goto done;
3069 err = got_object_open_as_tree(&tree2, repo, tree_id2);
3070 if (err)
3071 goto done;
3073 arg.worktree = worktree;
3074 arg.fileindex = fileindex;
3075 arg.progress_cb = progress_cb;
3076 arg.progress_arg = progress_arg;
3077 arg.cancel_cb = cancel_cb;
3078 arg.cancel_arg = cancel_arg;
3079 arg.label_orig = label_orig;
3080 arg.commit_id2 = commit_id2;
3081 err = got_diff_tree(tree1, tree2, "", "", repo, merge_file_cb, &arg, 1);
3082 sync_err = sync_fileindex(fileindex, fileindex_path);
3083 if (sync_err && err == NULL)
3084 err = sync_err;
3085 done:
3086 if (tree1)
3087 got_object_tree_close(tree1);
3088 if (tree2)
3089 got_object_tree_close(tree2);
3090 free(label_orig);
3091 return err;
3094 const struct got_error *
3095 got_worktree_merge_files(struct got_worktree *worktree,
3096 struct got_object_id *commit_id1, struct got_object_id *commit_id2,
3097 struct got_repository *repo, got_worktree_checkout_cb progress_cb,
3098 void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg)
3100 const struct got_error *err, *unlockerr;
3101 char *fileindex_path = NULL;
3102 struct got_fileindex *fileindex = NULL;
3103 struct check_merge_ok_arg mok_arg;
3105 err = lock_worktree(worktree, LOCK_EX);
3106 if (err)
3107 return err;
3109 err = open_fileindex(&fileindex, &fileindex_path, worktree);
3110 if (err)
3111 goto done;
3113 mok_arg.worktree = worktree;
3114 mok_arg.repo = repo;
3115 err = got_fileindex_for_each_entry_safe(fileindex, check_merge_ok,
3116 &mok_arg);
3117 if (err)
3118 goto done;
3120 err = merge_files(worktree, fileindex, fileindex_path, commit_id1,
3121 commit_id2, repo, progress_cb, progress_arg, cancel_cb, cancel_arg);
3122 done:
3123 if (fileindex)
3124 got_fileindex_free(fileindex);
3125 free(fileindex_path);
3126 unlockerr = lock_worktree(worktree, LOCK_SH);
3127 if (unlockerr && err == NULL)
3128 err = unlockerr;
3129 return err;
3132 struct diff_dir_cb_arg {
3133 struct got_fileindex *fileindex;
3134 struct got_worktree *worktree;
3135 const char *status_path;
3136 size_t status_path_len;
3137 struct got_repository *repo;
3138 got_worktree_status_cb status_cb;
3139 void *status_arg;
3140 got_cancel_cb cancel_cb;
3141 void *cancel_arg;
3142 /* A pathlist containing per-directory pathlists of ignore patterns. */
3143 struct got_pathlist_head ignores;
3144 int report_unchanged;
3145 int no_ignores;
3148 static const struct got_error *
3149 report_file_status(struct got_fileindex_entry *ie, const char *abspath,
3150 int dirfd, const char *de_name,
3151 got_worktree_status_cb status_cb, void *status_arg,
3152 struct got_repository *repo, int report_unchanged)
3154 const struct got_error *err = NULL;
3155 unsigned char status = GOT_STATUS_NO_CHANGE;
3156 unsigned char staged_status = get_staged_status(ie);
3157 struct stat sb;
3158 struct got_object_id blob_id, commit_id, staged_blob_id;
3159 struct got_object_id *blob_idp = NULL, *commit_idp = NULL;
3160 struct got_object_id *staged_blob_idp = NULL;
3162 err = get_file_status(&status, &sb, ie, abspath, dirfd, de_name, repo);
3163 if (err)
3164 return err;
3166 if (status == GOT_STATUS_NO_CHANGE &&
3167 staged_status == GOT_STATUS_NO_CHANGE && !report_unchanged)
3168 return NULL;
3170 if (got_fileindex_entry_has_blob(ie)) {
3171 memcpy(blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
3172 blob_idp = &blob_id;
3174 if (got_fileindex_entry_has_commit(ie)) {
3175 memcpy(commit_id.sha1, ie->commit_sha1, SHA1_DIGEST_LENGTH);
3176 commit_idp = &commit_id;
3178 if (staged_status == GOT_STATUS_ADD ||
3179 staged_status == GOT_STATUS_MODIFY) {
3180 memcpy(staged_blob_id.sha1, ie->staged_blob_sha1,
3181 SHA1_DIGEST_LENGTH);
3182 staged_blob_idp = &staged_blob_id;
3185 return (*status_cb)(status_arg, status, staged_status,
3186 ie->path, blob_idp, staged_blob_idp, commit_idp, dirfd, de_name);
3189 static const struct got_error *
3190 status_old_new(void *arg, struct got_fileindex_entry *ie,
3191 struct dirent *de, const char *parent_path, int dirfd)
3193 const struct got_error *err = NULL;
3194 struct diff_dir_cb_arg *a = arg;
3195 char *abspath;
3197 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
3198 return got_error(GOT_ERR_CANCELLED);
3200 if (got_path_cmp(parent_path, a->status_path,
3201 strlen(parent_path), a->status_path_len) != 0 &&
3202 !got_path_is_child(parent_path, a->status_path, a->status_path_len))
3203 return NULL;
3205 if (parent_path[0]) {
3206 if (asprintf(&abspath, "%s/%s/%s", a->worktree->root_path,
3207 parent_path, de->d_name) == -1)
3208 return got_error_from_errno("asprintf");
3209 } else {
3210 if (asprintf(&abspath, "%s/%s", a->worktree->root_path,
3211 de->d_name) == -1)
3212 return got_error_from_errno("asprintf");
3215 err = report_file_status(ie, abspath, dirfd, de->d_name,
3216 a->status_cb, a->status_arg, a->repo, a->report_unchanged);
3217 free(abspath);
3218 return err;
3221 static const struct got_error *
3222 status_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path)
3224 struct diff_dir_cb_arg *a = arg;
3225 struct got_object_id blob_id, commit_id;
3226 unsigned char status;
3228 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
3229 return got_error(GOT_ERR_CANCELLED);
3231 if (!got_path_is_child(ie->path, a->status_path, a->status_path_len))
3232 return NULL;
3234 memcpy(blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
3235 memcpy(commit_id.sha1, ie->commit_sha1, SHA1_DIGEST_LENGTH);
3236 if (got_fileindex_entry_has_file_on_disk(ie))
3237 status = GOT_STATUS_MISSING;
3238 else
3239 status = GOT_STATUS_DELETE;
3240 return (*a->status_cb)(a->status_arg, status, get_staged_status(ie),
3241 ie->path, &blob_id, NULL, &commit_id, -1, NULL);
3244 void
3245 free_ignorelist(struct got_pathlist_head *ignorelist)
3247 struct got_pathlist_entry *pe;
3249 TAILQ_FOREACH(pe, ignorelist, entry)
3250 free((char *)pe->path);
3251 got_pathlist_free(ignorelist);
3254 void
3255 free_ignores(struct got_pathlist_head *ignores)
3257 struct got_pathlist_entry *pe;
3259 TAILQ_FOREACH(pe, ignores, entry) {
3260 struct got_pathlist_head *ignorelist = pe->data;
3261 free_ignorelist(ignorelist);
3262 free((char *)pe->path);
3264 got_pathlist_free(ignores);
3267 static const struct got_error *
3268 read_ignores(struct got_pathlist_head *ignores, const char *path, FILE *f)
3270 const struct got_error *err = NULL;
3271 struct got_pathlist_entry *pe = NULL;
3272 struct got_pathlist_head *ignorelist;
3273 char *line = NULL, *pattern, *dirpath = NULL;
3274 size_t linesize = 0;
3275 ssize_t linelen;
3277 ignorelist = calloc(1, sizeof(*ignorelist));
3278 if (ignorelist == NULL)
3279 return got_error_from_errno("calloc");
3280 TAILQ_INIT(ignorelist);
3282 while ((linelen = getline(&line, &linesize, f)) != -1) {
3283 if (linelen > 0 && line[linelen - 1] == '\n')
3284 line[linelen - 1] = '\0';
3286 /* Git's ignores may contain comments. */
3287 if (line[0] == '#')
3288 continue;
3290 /* Git's negated patterns are not (yet?) supported. */
3291 if (line[0] == '!')
3292 continue;
3294 if (asprintf(&pattern, "%s%s%s", path, path[0] ? "/" : "",
3295 line) == -1) {
3296 err = got_error_from_errno("asprintf");
3297 goto done;
3299 err = got_pathlist_insert(NULL, ignorelist, pattern, NULL);
3300 if (err)
3301 goto done;
3303 if (ferror(f)) {
3304 err = got_error_from_errno("getline");
3305 goto done;
3308 dirpath = strdup(path);
3309 if (dirpath == NULL) {
3310 err = got_error_from_errno("strdup");
3311 goto done;
3313 err = got_pathlist_insert(&pe, ignores, dirpath, ignorelist);
3314 done:
3315 free(line);
3316 if (err || pe == NULL) {
3317 free(dirpath);
3318 free_ignorelist(ignorelist);
3320 return err;
3323 int
3324 match_ignores(struct got_pathlist_head *ignores, const char *path)
3326 struct got_pathlist_entry *pe;
3328 /* Handle patterns which match in all directories. */
3329 TAILQ_FOREACH(pe, ignores, entry) {
3330 struct got_pathlist_head *ignorelist = pe->data;
3331 struct got_pathlist_entry *pi;
3333 TAILQ_FOREACH(pi, ignorelist, entry) {
3334 const char *p, *pattern = pi->path;
3336 if (strncmp(pattern, "**/", 3) != 0)
3337 continue;
3338 pattern += 3;
3339 p = path;
3340 while (*p) {
3341 if (fnmatch(pattern, p,
3342 FNM_PATHNAME | FNM_LEADING_DIR)) {
3343 /* Retry in next directory. */
3344 while (*p && *p != '/')
3345 p++;
3346 while (*p == '/')
3347 p++;
3348 continue;
3350 return 1;
3356 * The ignores pathlist contains ignore lists from children before
3357 * parents, so we can find the most specific ignorelist by walking
3358 * ignores backwards.
3360 pe = TAILQ_LAST(ignores, got_pathlist_head);
3361 while (pe) {
3362 if (got_path_is_child(path, pe->path, pe->path_len)) {
3363 struct got_pathlist_head *ignorelist = pe->data;
3364 struct got_pathlist_entry *pi;
3365 TAILQ_FOREACH(pi, ignorelist, entry) {
3366 const char *pattern = pi->path;
3367 int flags = FNM_LEADING_DIR;
3368 if (strstr(pattern, "/**/") == NULL)
3369 flags |= FNM_PATHNAME;
3370 if (fnmatch(pattern, path, flags))
3371 continue;
3372 return 1;
3375 pe = TAILQ_PREV(pe, got_pathlist_head, entry);
3378 return 0;
3381 static const struct got_error *
3382 add_ignores(struct got_pathlist_head *ignores, const char *root_path,
3383 const char *path, int dirfd, const char *ignores_filename)
3385 const struct got_error *err = NULL;
3386 char *ignorespath;
3387 int fd = -1;
3388 FILE *ignoresfile = NULL;
3390 if (asprintf(&ignorespath, "%s/%s%s%s", root_path, path,
3391 path[0] ? "/" : "", ignores_filename) == -1)
3392 return got_error_from_errno("asprintf");
3394 if (dirfd != -1) {
3395 fd = openat(dirfd, ignores_filename, O_RDONLY | O_NOFOLLOW);
3396 if (fd == -1) {
3397 if (errno != ENOENT && errno != EACCES)
3398 err = got_error_from_errno2("openat",
3399 ignorespath);
3400 } else {
3401 ignoresfile = fdopen(fd, "r");
3402 if (ignoresfile == NULL)
3403 err = got_error_from_errno2("fdopen",
3404 ignorespath);
3405 else {
3406 fd = -1;
3407 err = read_ignores(ignores, path, ignoresfile);
3410 } else {
3411 ignoresfile = fopen(ignorespath, "r");
3412 if (ignoresfile == NULL) {
3413 if (errno != ENOENT && errno != EACCES)
3414 err = got_error_from_errno2("fopen",
3415 ignorespath);
3416 } else
3417 err = read_ignores(ignores, path, ignoresfile);
3420 if (ignoresfile && fclose(ignoresfile) == EOF && err == NULL)
3421 err = got_error_from_errno2("fclose", path);
3422 if (fd != -1 && close(fd) == -1 && err == NULL)
3423 err = got_error_from_errno2("close", path);
3424 free(ignorespath);
3425 return err;
3428 static const struct got_error *
3429 status_new(void *arg, struct dirent *de, const char *parent_path, int dirfd)
3431 const struct got_error *err = NULL;
3432 struct diff_dir_cb_arg *a = arg;
3433 char *path = NULL;
3435 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
3436 return got_error(GOT_ERR_CANCELLED);
3438 if (parent_path[0]) {
3439 if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1)
3440 return got_error_from_errno("asprintf");
3441 } else {
3442 path = de->d_name;
3445 if (de->d_type != DT_DIR &&
3446 got_path_is_child(path, a->status_path, a->status_path_len)
3447 && !match_ignores(&a->ignores, path))
3448 err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED,
3449 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3450 if (parent_path[0])
3451 free(path);
3452 return err;
3455 static const struct got_error *
3456 status_traverse(void *arg, const char *path, int dirfd)
3458 const struct got_error *err = NULL;
3459 struct diff_dir_cb_arg *a = arg;
3461 if (a->no_ignores)
3462 return NULL;
3464 err = add_ignores(&a->ignores, a->worktree->root_path,
3465 path, dirfd, ".cvsignore");
3466 if (err)
3467 return err;
3469 err = add_ignores(&a->ignores, a->worktree->root_path, path,
3470 dirfd, ".gitignore");
3472 return err;
3475 static const struct got_error *
3476 report_single_file_status(const char *path, const char *ondisk_path,
3477 struct got_fileindex *fileindex, got_worktree_status_cb status_cb,
3478 void *status_arg, struct got_repository *repo, int report_unchanged)
3480 struct got_fileindex_entry *ie;
3481 struct stat sb;
3483 ie = got_fileindex_entry_get(fileindex, path, strlen(path));
3484 if (ie)
3485 return report_file_status(ie, ondisk_path, -1, NULL,
3486 status_cb, status_arg, repo, report_unchanged);
3488 if (lstat(ondisk_path, &sb) == -1) {
3489 if (errno != ENOENT)
3490 return got_error_from_errno2("lstat", ondisk_path);
3491 return (*status_cb)(status_arg, GOT_STATUS_NONEXISTENT,
3492 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3493 return NULL;
3496 if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode))
3497 return (*status_cb)(status_arg, GOT_STATUS_UNVERSIONED,
3498 GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
3500 return NULL;
3503 static const struct got_error *
3504 add_ignores_from_parent_paths(struct got_pathlist_head *ignores,
3505 const char *root_path, const char *path)
3507 const struct got_error *err;
3508 char *parent_path, *next_parent_path = NULL;
3510 err = add_ignores(ignores, root_path, "", -1,
3511 ".cvsignore");
3512 if (err)
3513 return err;
3515 err = add_ignores(ignores, root_path, "", -1,
3516 ".gitignore");
3517 if (err)
3518 return err;
3520 err = got_path_dirname(&parent_path, path);
3521 if (err) {
3522 if (err->code == GOT_ERR_BAD_PATH)
3523 return NULL; /* cannot traverse parent */
3524 return err;
3526 for (;;) {
3527 err = add_ignores(ignores, root_path, parent_path, -1,
3528 ".cvsignore");
3529 if (err)
3530 break;
3531 err = add_ignores(ignores, root_path, parent_path, -1,
3532 ".gitignore");
3533 if (err)
3534 break;
3535 err = got_path_dirname(&next_parent_path, parent_path);
3536 if (err) {
3537 if (err->code == GOT_ERR_BAD_PATH)
3538 err = NULL; /* traversed everything */
3539 break;
3541 free(parent_path);
3542 parent_path = next_parent_path;
3543 next_parent_path = NULL;
3546 free(parent_path);
3547 free(next_parent_path);
3548 return err;
3551 static const struct got_error *
3552 worktree_status(struct got_worktree *worktree, const char *path,
3553 struct got_fileindex *fileindex, struct got_repository *repo,
3554 got_worktree_status_cb status_cb, void *status_arg,
3555 got_cancel_cb cancel_cb, void *cancel_arg, int no_ignores,
3556 int report_unchanged)
3558 const struct got_error *err = NULL;
3559 int fd = -1;
3560 struct got_fileindex_diff_dir_cb fdiff_cb;
3561 struct diff_dir_cb_arg arg;
3562 char *ondisk_path = NULL;
3564 TAILQ_INIT(&arg.ignores);
3566 if (asprintf(&ondisk_path, "%s%s%s",
3567 worktree->root_path, path[0] ? "/" : "", path) == -1)
3568 return got_error_from_errno("asprintf");
3570 fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY);
3571 if (fd == -1) {
3572 if (errno != ENOTDIR && errno != ENOENT && errno != EACCES &&
3573 errno != ELOOP)
3574 err = got_error_from_errno2("open", ondisk_path);
3575 else
3576 err = report_single_file_status(path, ondisk_path,
3577 fileindex, status_cb, status_arg, repo,
3578 report_unchanged);
3579 } else {
3580 fdiff_cb.diff_old_new = status_old_new;
3581 fdiff_cb.diff_old = status_old;
3582 fdiff_cb.diff_new = status_new;
3583 fdiff_cb.diff_traverse = status_traverse;
3584 arg.fileindex = fileindex;
3585 arg.worktree = worktree;
3586 arg.status_path = path;
3587 arg.status_path_len = strlen(path);
3588 arg.repo = repo;
3589 arg.status_cb = status_cb;
3590 arg.status_arg = status_arg;
3591 arg.cancel_cb = cancel_cb;
3592 arg.cancel_arg = cancel_arg;
3593 arg.report_unchanged = report_unchanged;
3594 arg.no_ignores = no_ignores;
3595 if (!no_ignores) {
3596 err = add_ignores_from_parent_paths(&arg.ignores,
3597 worktree->root_path, path);
3598 if (err)
3599 goto done;
3601 err = got_fileindex_diff_dir(fileindex, fd,
3602 worktree->root_path, path, repo, &fdiff_cb, &arg);
3604 done:
3605 free_ignores(&arg.ignores);
3606 if (fd != -1 && close(fd) != 0 && err == NULL)
3607 err = got_error_from_errno("close");
3608 free(ondisk_path);
3609 return err;
3612 const struct got_error *
3613 got_worktree_status(struct got_worktree *worktree,
3614 struct got_pathlist_head *paths, struct got_repository *repo,
3615 got_worktree_status_cb status_cb, void *status_arg,
3616 got_cancel_cb cancel_cb, void *cancel_arg)
3618 const struct got_error *err = NULL;
3619 char *fileindex_path = NULL;
3620 struct got_fileindex *fileindex = NULL;
3621 struct got_pathlist_entry *pe;
3623 err = open_fileindex(&fileindex, &fileindex_path, worktree);
3624 if (err)
3625 return err;
3627 TAILQ_FOREACH(pe, paths, entry) {
3628 err = worktree_status(worktree, pe->path, fileindex, repo,
3629 status_cb, status_arg, cancel_cb, cancel_arg, 0, 0);
3630 if (err)
3631 break;
3633 free(fileindex_path);
3634 got_fileindex_free(fileindex);
3635 return err;
3638 const struct got_error *
3639 got_worktree_resolve_path(char **wt_path, struct got_worktree *worktree,
3640 const char *arg)
3642 const struct got_error *err = NULL;
3643 char *resolved = NULL, *cwd = NULL, *path = NULL;
3644 size_t len;
3645 struct stat sb;
3646 char *abspath = NULL;
3647 char canonpath[PATH_MAX];
3649 *wt_path = NULL;
3651 cwd = getcwd(NULL, 0);
3652 if (cwd == NULL)
3653 return got_error_from_errno("getcwd");
3655 if (lstat(arg, &sb) == -1) {
3656 if (errno != ENOENT) {
3657 err = got_error_from_errno2("lstat", arg);
3658 goto done;
3660 sb.st_mode = 0;
3662 if (S_ISLNK(sb.st_mode)) {
3664 * We cannot use realpath(3) with symlinks since we want to
3665 * operate on the symlink itself.
3666 * But we can make the path absolute, assuming it is relative
3667 * to the current working directory, and then canonicalize it.
3669 if (!got_path_is_absolute(arg)) {
3670 if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) {
3671 err = got_error_from_errno("asprintf");
3672 goto done;
3676 err = got_canonpath(abspath ? abspath : arg, canonpath,
3677 sizeof(canonpath));
3678 if (err)
3679 goto done;
3680 resolved = strdup(canonpath);
3681 if (resolved == NULL) {
3682 err = got_error_from_errno("strdup");
3683 goto done;
3685 } else {
3686 resolved = realpath(arg, NULL);
3687 if (resolved == NULL) {
3688 if (errno != ENOENT) {
3689 err = got_error_from_errno2("realpath", arg);
3690 goto done;
3692 if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) {
3693 err = got_error_from_errno("asprintf");
3694 goto done;
3696 err = got_canonpath(abspath, canonpath,
3697 sizeof(canonpath));
3698 if (err)
3699 goto done;
3700 resolved = strdup(canonpath);
3701 if (resolved == NULL) {
3702 err = got_error_from_errno("strdup");
3703 goto done;
3708 if (strncmp(got_worktree_get_root_path(worktree), resolved,
3709 strlen(got_worktree_get_root_path(worktree)))) {
3710 err = got_error_path(resolved, GOT_ERR_BAD_PATH);
3711 goto done;
3714 if (strlen(resolved) > strlen(got_worktree_get_root_path(worktree))) {
3715 err = got_path_skip_common_ancestor(&path,
3716 got_worktree_get_root_path(worktree), resolved);
3717 if (err)
3718 goto done;
3719 } else {
3720 path = strdup("");
3721 if (path == NULL) {
3722 err = got_error_from_errno("strdup");
3723 goto done;
3727 /* XXX status walk can't deal with trailing slash! */
3728 len = strlen(path);
3729 while (len > 0 && path[len - 1] == '/') {
3730 path[len - 1] = '\0';
3731 len--;
3733 done:
3734 free(abspath);
3735 free(resolved);
3736 free(cwd);
3737 if (err == NULL)
3738 *wt_path = path;
3739 else
3740 free(path);
3741 return err;
3744 struct schedule_addition_args {
3745 struct got_worktree *worktree;
3746 struct got_fileindex *fileindex;
3747 got_worktree_checkout_cb progress_cb;
3748 void *progress_arg;
3749 struct got_repository *repo;
3752 static const struct got_error *
3753 schedule_addition(void *arg, unsigned char status, unsigned char staged_status,
3754 const char *relpath, struct got_object_id *blob_id,
3755 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
3756 int dirfd, const char *de_name)
3758 struct schedule_addition_args *a = arg;
3759 const struct got_error *err = NULL;
3760 struct got_fileindex_entry *ie;
3761 struct stat sb;
3762 char *ondisk_path;
3764 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
3765 relpath) == -1)
3766 return got_error_from_errno("asprintf");
3768 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
3769 if (ie) {
3770 err = get_file_status(&status, &sb, ie, ondisk_path, dirfd,
3771 de_name, a->repo);
3772 if (err)
3773 goto done;
3774 /* Re-adding an existing entry is a no-op. */
3775 if (status == GOT_STATUS_ADD)
3776 goto done;
3777 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
3778 if (err)
3779 goto done;
3782 if (status != GOT_STATUS_UNVERSIONED) {
3783 err = got_error_path(ondisk_path, GOT_ERR_FILE_STATUS);
3784 goto done;
3787 err = got_fileindex_entry_alloc(&ie, relpath);
3788 if (err)
3789 goto done;
3790 err = got_fileindex_entry_update(ie, a->worktree->root_fd,
3791 relpath, NULL, NULL, 1);
3792 if (err) {
3793 got_fileindex_entry_free(ie);
3794 goto done;
3796 err = got_fileindex_entry_add(a->fileindex, ie);
3797 if (err) {
3798 got_fileindex_entry_free(ie);
3799 goto done;
3801 done:
3802 free(ondisk_path);
3803 if (err)
3804 return err;
3805 if (status == GOT_STATUS_ADD)
3806 return NULL;
3807 return (*a->progress_cb)(a->progress_arg, GOT_STATUS_ADD, relpath);
3810 const struct got_error *
3811 got_worktree_schedule_add(struct got_worktree *worktree,
3812 struct got_pathlist_head *paths,
3813 got_worktree_checkout_cb progress_cb, void *progress_arg,
3814 struct got_repository *repo, int no_ignores)
3816 struct got_fileindex *fileindex = NULL;
3817 char *fileindex_path = NULL;
3818 const struct got_error *err = NULL, *sync_err, *unlockerr;
3819 struct got_pathlist_entry *pe;
3820 struct schedule_addition_args saa;
3822 err = lock_worktree(worktree, LOCK_EX);
3823 if (err)
3824 return err;
3826 err = open_fileindex(&fileindex, &fileindex_path, worktree);
3827 if (err)
3828 goto done;
3830 saa.worktree = worktree;
3831 saa.fileindex = fileindex;
3832 saa.progress_cb = progress_cb;
3833 saa.progress_arg = progress_arg;
3834 saa.repo = repo;
3836 TAILQ_FOREACH(pe, paths, entry) {
3837 err = worktree_status(worktree, pe->path, fileindex, repo,
3838 schedule_addition, &saa, NULL, NULL, no_ignores, 0);
3839 if (err)
3840 break;
3842 sync_err = sync_fileindex(fileindex, fileindex_path);
3843 if (sync_err && err == NULL)
3844 err = sync_err;
3845 done:
3846 free(fileindex_path);
3847 if (fileindex)
3848 got_fileindex_free(fileindex);
3849 unlockerr = lock_worktree(worktree, LOCK_SH);
3850 if (unlockerr && err == NULL)
3851 err = unlockerr;
3852 return err;
3855 struct schedule_deletion_args {
3856 struct got_worktree *worktree;
3857 struct got_fileindex *fileindex;
3858 got_worktree_delete_cb progress_cb;
3859 void *progress_arg;
3860 struct got_repository *repo;
3861 int delete_local_mods;
3862 int keep_on_disk;
3863 const char *status_codes;
3866 static const struct got_error *
3867 schedule_for_deletion(void *arg, unsigned char status,
3868 unsigned char staged_status, const char *relpath,
3869 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
3870 struct got_object_id *commit_id, int dirfd, const char *de_name)
3872 struct schedule_deletion_args *a = arg;
3873 const struct got_error *err = NULL;
3874 struct got_fileindex_entry *ie = NULL;
3875 struct stat sb;
3876 char *ondisk_path;
3878 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
3879 if (ie == NULL)
3880 return got_error_path(relpath, GOT_ERR_BAD_PATH);
3882 staged_status = get_staged_status(ie);
3883 if (staged_status != GOT_STATUS_NO_CHANGE) {
3884 if (staged_status == GOT_STATUS_DELETE)
3885 return NULL;
3886 return got_error_path(relpath, GOT_ERR_FILE_STAGED);
3889 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
3890 relpath) == -1)
3891 return got_error_from_errno("asprintf");
3893 err = get_file_status(&status, &sb, ie, ondisk_path, dirfd, de_name,
3894 a->repo);
3895 if (err)
3896 goto done;
3898 if (a->status_codes) {
3899 size_t ncodes = strlen(a->status_codes);
3900 int i;
3901 for (i = 0; i < ncodes ; i++) {
3902 if (status == a->status_codes[i])
3903 break;
3905 if (i == ncodes) {
3906 /* Do not delete files in non-matching status. */
3907 free(ondisk_path);
3908 return NULL;
3910 if (a->status_codes[i] != GOT_STATUS_MODIFY &&
3911 a->status_codes[i] != GOT_STATUS_MISSING) {
3912 static char msg[64];
3913 snprintf(msg, sizeof(msg),
3914 "invalid status code '%c'", a->status_codes[i]);
3915 err = got_error_msg(GOT_ERR_FILE_STATUS, msg);
3916 goto done;
3920 if (status != GOT_STATUS_NO_CHANGE) {
3921 if (status == GOT_STATUS_DELETE)
3922 goto done;
3923 if (status == GOT_STATUS_MODIFY && !a->delete_local_mods) {
3924 err = got_error_path(relpath, GOT_ERR_FILE_MODIFIED);
3925 goto done;
3927 if (status != GOT_STATUS_MODIFY &&
3928 status != GOT_STATUS_MISSING) {
3929 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
3930 goto done;
3934 if (!a->keep_on_disk && status != GOT_STATUS_MISSING) {
3935 size_t root_len;
3937 if (dirfd != -1) {
3938 if (unlinkat(dirfd, de_name, 0) != 0) {
3939 err = got_error_from_errno2("unlinkat",
3940 ondisk_path);
3941 goto done;
3943 } else if (unlink(ondisk_path) != 0) {
3944 err = got_error_from_errno2("unlink", ondisk_path);
3945 goto done;
3948 root_len = strlen(a->worktree->root_path);
3949 do {
3950 char *parent;
3951 err = got_path_dirname(&parent, ondisk_path);
3952 if (err)
3953 goto done;
3954 free(ondisk_path);
3955 ondisk_path = parent;
3956 if (rmdir(ondisk_path) == -1) {
3957 if (errno != ENOTEMPTY)
3958 err = got_error_from_errno2("rmdir",
3959 ondisk_path);
3960 break;
3962 } while (got_path_cmp(ondisk_path, a->worktree->root_path,
3963 strlen(ondisk_path), root_len) != 0);
3966 got_fileindex_entry_mark_deleted_from_disk(ie);
3967 done:
3968 free(ondisk_path);
3969 if (err)
3970 return err;
3971 if (status == GOT_STATUS_DELETE)
3972 return NULL;
3973 return (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE,
3974 staged_status, relpath);
3977 const struct got_error *
3978 got_worktree_schedule_delete(struct got_worktree *worktree,
3979 struct got_pathlist_head *paths, int delete_local_mods,
3980 const char *status_codes,
3981 got_worktree_delete_cb progress_cb, void *progress_arg,
3982 struct got_repository *repo, int keep_on_disk)
3984 struct got_fileindex *fileindex = NULL;
3985 char *fileindex_path = NULL;
3986 const struct got_error *err = NULL, *sync_err, *unlockerr;
3987 struct got_pathlist_entry *pe;
3988 struct schedule_deletion_args sda;
3990 err = lock_worktree(worktree, LOCK_EX);
3991 if (err)
3992 return err;
3994 err = open_fileindex(&fileindex, &fileindex_path, worktree);
3995 if (err)
3996 goto done;
3998 sda.worktree = worktree;
3999 sda.fileindex = fileindex;
4000 sda.progress_cb = progress_cb;
4001 sda.progress_arg = progress_arg;
4002 sda.repo = repo;
4003 sda.delete_local_mods = delete_local_mods;
4004 sda.keep_on_disk = keep_on_disk;
4005 sda.status_codes = status_codes;
4007 TAILQ_FOREACH(pe, paths, entry) {
4008 err = worktree_status(worktree, pe->path, fileindex, repo,
4009 schedule_for_deletion, &sda, NULL, NULL, 0, 1);
4010 if (err)
4011 break;
4013 sync_err = sync_fileindex(fileindex, fileindex_path);
4014 if (sync_err && err == NULL)
4015 err = sync_err;
4016 done:
4017 free(fileindex_path);
4018 if (fileindex)
4019 got_fileindex_free(fileindex);
4020 unlockerr = lock_worktree(worktree, LOCK_SH);
4021 if (unlockerr && err == NULL)
4022 err = unlockerr;
4023 return err;
4026 static const struct got_error *
4027 copy_one_line(FILE *infile, FILE *outfile, FILE *rejectfile)
4029 const struct got_error *err = NULL;
4030 char *line = NULL;
4031 size_t linesize = 0, n;
4032 ssize_t linelen;
4034 linelen = getline(&line, &linesize, infile);
4035 if (linelen == -1) {
4036 if (ferror(infile)) {
4037 err = got_error_from_errno("getline");
4038 goto done;
4040 return NULL;
4042 if (outfile) {
4043 n = fwrite(line, 1, linelen, outfile);
4044 if (n != linelen) {
4045 err = got_ferror(outfile, GOT_ERR_IO);
4046 goto done;
4049 if (rejectfile) {
4050 n = fwrite(line, 1, linelen, rejectfile);
4051 if (n != linelen)
4052 err = got_ferror(outfile, GOT_ERR_IO);
4054 done:
4055 free(line);
4056 return err;
4059 static const struct got_error *
4060 skip_one_line(FILE *f)
4062 char *line = NULL;
4063 size_t linesize = 0;
4064 ssize_t linelen;
4066 linelen = getline(&line, &linesize, f);
4067 if (linelen == -1) {
4068 if (ferror(f))
4069 return got_error_from_errno("getline");
4070 return NULL;
4072 free(line);
4073 return NULL;
4076 static const struct got_error *
4077 copy_change(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4078 int start_old, int end_old, int start_new, int end_new,
4079 FILE *outfile, FILE *rejectfile)
4081 const struct got_error *err;
4083 /* Copy old file's lines leading up to patch. */
4084 while (!feof(f1) && *line_cur1 < start_old) {
4085 err = copy_one_line(f1, outfile, NULL);
4086 if (err)
4087 return err;
4088 (*line_cur1)++;
4090 /* Skip new file's lines leading up to patch. */
4091 while (!feof(f2) && *line_cur2 < start_new) {
4092 if (rejectfile)
4093 err = copy_one_line(f2, NULL, rejectfile);
4094 else
4095 err = skip_one_line(f2);
4096 if (err)
4097 return err;
4098 (*line_cur2)++;
4100 /* Copy patched lines. */
4101 while (!feof(f2) && *line_cur2 <= end_new) {
4102 err = copy_one_line(f2, outfile, NULL);
4103 if (err)
4104 return err;
4105 (*line_cur2)++;
4107 /* Skip over old file's replaced lines. */
4108 while (!feof(f1) && *line_cur1 <= end_old) {
4109 if (rejectfile)
4110 err = copy_one_line(f1, NULL, rejectfile);
4111 else
4112 err = skip_one_line(f1);
4113 if (err)
4114 return err;
4115 (*line_cur1)++;
4118 return NULL;
4121 static const struct got_error *
4122 copy_remaining_content(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4123 FILE *outfile, FILE *rejectfile)
4125 const struct got_error *err;
4127 if (outfile) {
4128 /* Copy old file's lines until EOF. */
4129 while (!feof(f1)) {
4130 err = copy_one_line(f1, outfile, NULL);
4131 if (err)
4132 return err;
4133 (*line_cur1)++;
4136 if (rejectfile) {
4137 /* Copy new file's lines until EOF. */
4138 while (!feof(f2)) {
4139 err = copy_one_line(f2, NULL, rejectfile);
4140 if (err)
4141 return err;
4142 (*line_cur2)++;
4146 return NULL;
4149 static const struct got_error *
4150 apply_or_reject_change(int *choice, int *nchunks_used,
4151 struct diff_result *diff_result, int n,
4152 const char *relpath, FILE *f1, FILE *f2, int *line_cur1, int *line_cur2,
4153 FILE *outfile, FILE *rejectfile, int changeno, int nchanges,
4154 got_worktree_patch_cb patch_cb, void *patch_arg)
4156 const struct got_error *err = NULL;
4157 struct diff_chunk_context cc = {};
4158 int start_old, end_old, start_new, end_new;
4159 FILE *hunkfile;
4160 struct diff_output_unidiff_state *diff_state;
4161 struct diff_input_info diff_info;
4162 int rc;
4164 *choice = GOT_PATCH_CHOICE_NONE;
4166 /* Get changed line numbers without context lines for copy_change(). */
4167 diff_chunk_context_load_change(&cc, NULL, diff_result, n, 0);
4168 start_old = cc.left.start;
4169 end_old = cc.left.end;
4170 start_new = cc.right.start;
4171 end_new = cc.right.end;
4173 /* Get the same change with context lines for display. */
4174 memset(&cc, 0, sizeof(cc));
4175 diff_chunk_context_load_change(&cc, nchunks_used, diff_result, n, 3);
4177 memset(&diff_info, 0, sizeof(diff_info));
4178 diff_info.left_path = relpath;
4179 diff_info.right_path = relpath;
4181 diff_state = diff_output_unidiff_state_alloc();
4182 if (diff_state == NULL)
4183 return got_error_set_errno(ENOMEM,
4184 "diff_output_unidiff_state_alloc");
4186 hunkfile = got_opentemp();
4187 if (hunkfile == NULL) {
4188 err = got_error_from_errno("got_opentemp");
4189 goto done;
4192 rc = diff_output_unidiff_chunk(NULL, hunkfile, diff_state, &diff_info,
4193 diff_result, &cc);
4194 if (rc != DIFF_RC_OK) {
4195 err = got_error_set_errno(rc, "diff_output_unidiff_chunk");
4196 goto done;
4199 if (fseek(hunkfile, 0L, SEEK_SET) == -1) {
4200 err = got_ferror(hunkfile, GOT_ERR_IO);
4201 goto done;
4204 err = (*patch_cb)(choice, patch_arg, GOT_STATUS_MODIFY, relpath,
4205 hunkfile, changeno, nchanges);
4206 if (err)
4207 goto done;
4209 switch (*choice) {
4210 case GOT_PATCH_CHOICE_YES:
4211 err = copy_change(f1, f2, line_cur1, line_cur2, start_old,
4212 end_old, start_new, end_new, outfile, rejectfile);
4213 break;
4214 case GOT_PATCH_CHOICE_NO:
4215 err = copy_change(f1, f2, line_cur1, line_cur2, start_old,
4216 end_old, start_new, end_new, rejectfile, outfile);
4217 break;
4218 case GOT_PATCH_CHOICE_QUIT:
4219 break;
4220 default:
4221 err = got_error(GOT_ERR_PATCH_CHOICE);
4222 break;
4224 done:
4225 diff_output_unidiff_state_free(diff_state);
4226 if (hunkfile && fclose(hunkfile) == EOF && err == NULL)
4227 err = got_error_from_errno("fclose");
4228 return err;
4231 struct revert_file_args {
4232 struct got_worktree *worktree;
4233 struct got_fileindex *fileindex;
4234 got_worktree_checkout_cb progress_cb;
4235 void *progress_arg;
4236 got_worktree_patch_cb patch_cb;
4237 void *patch_arg;
4238 struct got_repository *repo;
4241 static const struct got_error *
4242 create_patched_content(char **path_outfile, int reverse_patch,
4243 struct got_object_id *blob_id, const char *path2,
4244 int dirfd2, const char *de_name2,
4245 const char *relpath, struct got_repository *repo,
4246 got_worktree_patch_cb patch_cb, void *patch_arg)
4248 const struct got_error *err, *free_err;
4249 struct got_blob_object *blob = NULL;
4250 FILE *f1 = NULL, *f2 = NULL, *outfile = NULL;
4251 int fd2 = -1;
4252 char link_target[PATH_MAX];
4253 ssize_t link_len = 0;
4254 char *path1 = NULL, *id_str = NULL;
4255 struct stat sb2;
4256 struct got_diffreg_result *diffreg_result = NULL;
4257 int line_cur1 = 1, line_cur2 = 1, have_content = 0;
4258 int i = 0, n = 0, nchunks_used = 0, nchanges = 0;
4260 *path_outfile = NULL;
4262 err = got_object_id_str(&id_str, blob_id);
4263 if (err)
4264 return err;
4266 if (dirfd2 != -1) {
4267 fd2 = openat(dirfd2, de_name2, O_RDONLY | O_NOFOLLOW);
4268 if (fd2 == -1) {
4269 if (errno != ELOOP) {
4270 err = got_error_from_errno2("openat", path2);
4271 goto done;
4273 link_len = readlinkat(dirfd2, de_name2,
4274 link_target, sizeof(link_target));
4275 if (link_len == -1)
4276 return got_error_from_errno2("readlinkat", path2);
4277 sb2.st_mode = S_IFLNK;
4278 sb2.st_size = link_len;
4280 } else {
4281 fd2 = open(path2, O_RDONLY | O_NOFOLLOW);
4282 if (fd2 == -1) {
4283 if (errno != ELOOP) {
4284 err = got_error_from_errno2("open", path2);
4285 goto done;
4287 link_len = readlink(path2, link_target,
4288 sizeof(link_target));
4289 if (link_len == -1)
4290 return got_error_from_errno2("readlink", path2);
4291 sb2.st_mode = S_IFLNK;
4292 sb2.st_size = link_len;
4295 if (fd2 != -1) {
4296 if (fstat(fd2, &sb2) == -1) {
4297 err = got_error_from_errno2("fstat", path2);
4298 goto done;
4301 f2 = fdopen(fd2, "r");
4302 if (f2 == NULL) {
4303 err = got_error_from_errno2("fdopen", path2);
4304 goto done;
4306 fd2 = -1;
4307 } else {
4308 size_t n;
4309 f2 = got_opentemp();
4310 if (f2 == NULL) {
4311 err = got_error_from_errno2("got_opentemp", path2);
4312 goto done;
4314 n = fwrite(link_target, 1, link_len, f2);
4315 if (n != link_len) {
4316 err = got_ferror(f2, GOT_ERR_IO);
4317 goto done;
4319 if (fflush(f2) == EOF) {
4320 err = got_error_from_errno("fflush");
4321 goto done;
4323 rewind(f2);
4326 err = got_object_open_as_blob(&blob, repo, blob_id, 8192);
4327 if (err)
4328 goto done;
4330 err = got_opentemp_named(&path1, &f1, "got-patched-blob");
4331 if (err)
4332 goto done;
4334 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob);
4335 if (err)
4336 goto done;
4338 err = got_diff_files(&diffreg_result, f1, id_str, f2, path2, 3, 0, 1,
4339 NULL);
4340 if (err)
4341 goto done;
4343 err = got_opentemp_named(path_outfile, &outfile, "got-patched-content");
4344 if (err)
4345 goto done;
4347 if (fseek(f1, 0L, SEEK_SET) == -1)
4348 return got_ferror(f1, GOT_ERR_IO);
4349 if (fseek(f2, 0L, SEEK_SET) == -1)
4350 return got_ferror(f2, GOT_ERR_IO);
4352 /* Count the number of actual changes in the diff result. */
4353 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
4354 struct diff_chunk_context cc = {};
4355 diff_chunk_context_load_change(&cc, &nchunks_used,
4356 diffreg_result->result, n, 0);
4357 nchanges++;
4359 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
4360 int choice;
4361 err = apply_or_reject_change(&choice, &nchunks_used,
4362 diffreg_result->result, n, relpath, f1, f2,
4363 &line_cur1, &line_cur2,
4364 reverse_patch ? NULL : outfile,
4365 reverse_patch ? outfile : NULL,
4366 ++i, nchanges, patch_cb, patch_arg);
4367 if (err)
4368 goto done;
4369 if (choice == GOT_PATCH_CHOICE_YES)
4370 have_content = 1;
4371 else if (choice == GOT_PATCH_CHOICE_QUIT)
4372 break;
4374 if (have_content) {
4375 err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2,
4376 reverse_patch ? NULL : outfile,
4377 reverse_patch ? outfile : NULL);
4378 if (err)
4379 goto done;
4381 if (!S_ISLNK(sb2.st_mode)) {
4382 if (fchmod(fileno(outfile), sb2.st_mode) == -1) {
4383 err = got_error_from_errno2("fchmod", path2);
4384 goto done;
4388 done:
4389 free(id_str);
4390 if (blob)
4391 got_object_blob_close(blob);
4392 free_err = got_diffreg_result_free(diffreg_result);
4393 if (err == NULL)
4394 err = free_err;
4395 if (f1 && fclose(f1) == EOF && err == NULL)
4396 err = got_error_from_errno2("fclose", path1);
4397 if (f2 && fclose(f2) == EOF && err == NULL)
4398 err = got_error_from_errno2("fclose", path2);
4399 if (fd2 != -1 && close(fd2) == -1 && err == NULL)
4400 err = got_error_from_errno2("close", path2);
4401 if (outfile && fclose(outfile) == EOF && err == NULL)
4402 err = got_error_from_errno2("fclose", *path_outfile);
4403 if (path1 && unlink(path1) == -1 && err == NULL)
4404 err = got_error_from_errno2("unlink", path1);
4405 if (err || !have_content) {
4406 if (*path_outfile && unlink(*path_outfile) == -1 && err == NULL)
4407 err = got_error_from_errno2("unlink", *path_outfile);
4408 free(*path_outfile);
4409 *path_outfile = NULL;
4411 free(path1);
4412 return err;
4415 static const struct got_error *
4416 revert_file(void *arg, unsigned char status, unsigned char staged_status,
4417 const char *relpath, struct got_object_id *blob_id,
4418 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4419 int dirfd, const char *de_name)
4421 struct revert_file_args *a = arg;
4422 const struct got_error *err = NULL;
4423 char *parent_path = NULL;
4424 struct got_fileindex_entry *ie;
4425 struct got_tree_object *tree = NULL;
4426 struct got_object_id *tree_id = NULL;
4427 const struct got_tree_entry *te = NULL;
4428 char *tree_path = NULL, *te_name;
4429 char *ondisk_path = NULL, *path_content = NULL;
4430 struct got_blob_object *blob = NULL;
4432 /* Reverting a staged deletion is a no-op. */
4433 if (status == GOT_STATUS_DELETE &&
4434 staged_status != GOT_STATUS_NO_CHANGE)
4435 return NULL;
4437 if (status == GOT_STATUS_UNVERSIONED)
4438 return (*a->progress_cb)(a->progress_arg,
4439 GOT_STATUS_UNVERSIONED, relpath);
4441 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
4442 if (ie == NULL)
4443 return got_error_path(relpath, GOT_ERR_BAD_PATH);
4445 /* Construct in-repository path of tree which contains this blob. */
4446 err = got_path_dirname(&parent_path, ie->path);
4447 if (err) {
4448 if (err->code != GOT_ERR_BAD_PATH)
4449 goto done;
4450 parent_path = strdup("/");
4451 if (parent_path == NULL) {
4452 err = got_error_from_errno("strdup");
4453 goto done;
4456 if (got_path_is_root_dir(a->worktree->path_prefix)) {
4457 tree_path = strdup(parent_path);
4458 if (tree_path == NULL) {
4459 err = got_error_from_errno("strdup");
4460 goto done;
4462 } else {
4463 if (got_path_is_root_dir(parent_path)) {
4464 tree_path = strdup(a->worktree->path_prefix);
4465 if (tree_path == NULL) {
4466 err = got_error_from_errno("strdup");
4467 goto done;
4469 } else {
4470 if (asprintf(&tree_path, "%s/%s",
4471 a->worktree->path_prefix, parent_path) == -1) {
4472 err = got_error_from_errno("asprintf");
4473 goto done;
4478 err = got_object_id_by_path(&tree_id, a->repo,
4479 a->worktree->base_commit_id, tree_path);
4480 if (err) {
4481 if (!(err->code == GOT_ERR_NO_TREE_ENTRY &&
4482 (status == GOT_STATUS_ADD ||
4483 staged_status == GOT_STATUS_ADD)))
4484 goto done;
4485 } else {
4486 err = got_object_open_as_tree(&tree, a->repo, tree_id);
4487 if (err)
4488 goto done;
4490 err = got_path_basename(&te_name, ie->path);
4491 if (err)
4492 goto done;
4494 te = got_object_tree_find_entry(tree, te_name);
4495 free(te_name);
4496 if (te == NULL && status != GOT_STATUS_ADD &&
4497 staged_status != GOT_STATUS_ADD) {
4498 err = got_error_path(ie->path, GOT_ERR_NO_TREE_ENTRY);
4499 goto done;
4503 switch (status) {
4504 case GOT_STATUS_ADD:
4505 if (a->patch_cb) {
4506 int choice = GOT_PATCH_CHOICE_NONE;
4507 err = (*a->patch_cb)(&choice, a->patch_arg,
4508 status, ie->path, NULL, 1, 1);
4509 if (err)
4510 goto done;
4511 if (choice != GOT_PATCH_CHOICE_YES)
4512 break;
4514 err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_REVERT,
4515 ie->path);
4516 if (err)
4517 goto done;
4518 got_fileindex_entry_remove(a->fileindex, ie);
4519 break;
4520 case GOT_STATUS_DELETE:
4521 if (a->patch_cb) {
4522 int choice = GOT_PATCH_CHOICE_NONE;
4523 err = (*a->patch_cb)(&choice, a->patch_arg,
4524 status, ie->path, NULL, 1, 1);
4525 if (err)
4526 goto done;
4527 if (choice != GOT_PATCH_CHOICE_YES)
4528 break;
4530 /* fall through */
4531 case GOT_STATUS_MODIFY:
4532 case GOT_STATUS_MODE_CHANGE:
4533 case GOT_STATUS_CONFLICT:
4534 case GOT_STATUS_MISSING: {
4535 struct got_object_id id;
4536 if (staged_status == GOT_STATUS_ADD ||
4537 staged_status == GOT_STATUS_MODIFY) {
4538 memcpy(id.sha1, ie->staged_blob_sha1,
4539 SHA1_DIGEST_LENGTH);
4540 } else
4541 memcpy(id.sha1, ie->blob_sha1,
4542 SHA1_DIGEST_LENGTH);
4543 err = got_object_open_as_blob(&blob, a->repo, &id, 8192);
4544 if (err)
4545 goto done;
4547 if (asprintf(&ondisk_path, "%s/%s",
4548 got_worktree_get_root_path(a->worktree), relpath) == -1) {
4549 err = got_error_from_errno("asprintf");
4550 goto done;
4553 if (a->patch_cb && (status == GOT_STATUS_MODIFY ||
4554 status == GOT_STATUS_CONFLICT)) {
4555 int is_bad_symlink = 0;
4556 err = create_patched_content(&path_content, 1, &id,
4557 ondisk_path, dirfd, de_name, ie->path, a->repo,
4558 a->patch_cb, a->patch_arg);
4559 if (err || path_content == NULL)
4560 break;
4561 if (te && S_ISLNK(te->mode)) {
4562 if (unlink(path_content) == -1) {
4563 err = got_error_from_errno2("unlink",
4564 path_content);
4565 break;
4567 err = install_symlink(&is_bad_symlink,
4568 a->worktree, ondisk_path, ie->path,
4569 blob, 0, 1, 0, a->repo,
4570 a->progress_cb, a->progress_arg);
4571 } else {
4572 if (rename(path_content, ondisk_path) == -1) {
4573 err = got_error_from_errno3("rename",
4574 path_content, ondisk_path);
4575 goto done;
4578 } else {
4579 int is_bad_symlink = 0;
4580 if (te && S_ISLNK(te->mode)) {
4581 err = install_symlink(&is_bad_symlink,
4582 a->worktree, ondisk_path, ie->path,
4583 blob, 0, 1, 0, a->repo,
4584 a->progress_cb, a->progress_arg);
4585 } else {
4586 err = install_blob(a->worktree, ondisk_path,
4587 ie->path,
4588 te ? te->mode : GOT_DEFAULT_FILE_MODE,
4589 got_fileindex_perms_to_st(ie), blob,
4590 0, 1, 0, 0, a->repo,
4591 a->progress_cb, a->progress_arg);
4593 if (err)
4594 goto done;
4595 if (status == GOT_STATUS_DELETE ||
4596 status == GOT_STATUS_MODE_CHANGE) {
4597 err = got_fileindex_entry_update(ie,
4598 a->worktree->root_fd, relpath,
4599 blob->id.sha1,
4600 a->worktree->base_commit_id->sha1, 1);
4601 if (err)
4602 goto done;
4604 if (is_bad_symlink) {
4605 got_fileindex_entry_filetype_set(ie,
4606 GOT_FILEIDX_MODE_BAD_SYMLINK);
4609 break;
4611 default:
4612 break;
4614 done:
4615 free(ondisk_path);
4616 free(path_content);
4617 free(parent_path);
4618 free(tree_path);
4619 if (blob)
4620 got_object_blob_close(blob);
4621 if (tree)
4622 got_object_tree_close(tree);
4623 free(tree_id);
4624 return err;
4627 const struct got_error *
4628 got_worktree_revert(struct got_worktree *worktree,
4629 struct got_pathlist_head *paths,
4630 got_worktree_checkout_cb progress_cb, void *progress_arg,
4631 got_worktree_patch_cb patch_cb, void *patch_arg,
4632 struct got_repository *repo)
4634 struct got_fileindex *fileindex = NULL;
4635 char *fileindex_path = NULL;
4636 const struct got_error *err = NULL, *unlockerr = NULL;
4637 const struct got_error *sync_err = NULL;
4638 struct got_pathlist_entry *pe;
4639 struct revert_file_args rfa;
4641 err = lock_worktree(worktree, LOCK_EX);
4642 if (err)
4643 return err;
4645 err = open_fileindex(&fileindex, &fileindex_path, worktree);
4646 if (err)
4647 goto done;
4649 rfa.worktree = worktree;
4650 rfa.fileindex = fileindex;
4651 rfa.progress_cb = progress_cb;
4652 rfa.progress_arg = progress_arg;
4653 rfa.patch_cb = patch_cb;
4654 rfa.patch_arg = patch_arg;
4655 rfa.repo = repo;
4656 TAILQ_FOREACH(pe, paths, entry) {
4657 err = worktree_status(worktree, pe->path, fileindex, repo,
4658 revert_file, &rfa, NULL, NULL, 0, 0);
4659 if (err)
4660 break;
4662 sync_err = sync_fileindex(fileindex, fileindex_path);
4663 if (sync_err && err == NULL)
4664 err = sync_err;
4665 done:
4666 free(fileindex_path);
4667 if (fileindex)
4668 got_fileindex_free(fileindex);
4669 unlockerr = lock_worktree(worktree, LOCK_SH);
4670 if (unlockerr && err == NULL)
4671 err = unlockerr;
4672 return err;
4675 static void
4676 free_commitable(struct got_commitable *ct)
4678 free(ct->path);
4679 free(ct->in_repo_path);
4680 free(ct->ondisk_path);
4681 free(ct->blob_id);
4682 free(ct->base_blob_id);
4683 free(ct->staged_blob_id);
4684 free(ct->base_commit_id);
4685 free(ct);
4688 struct collect_commitables_arg {
4689 struct got_pathlist_head *commitable_paths;
4690 struct got_repository *repo;
4691 struct got_worktree *worktree;
4692 struct got_fileindex *fileindex;
4693 int have_staged_files;
4694 int allow_bad_symlinks;
4697 static const struct got_error *
4698 collect_commitables(void *arg, unsigned char status,
4699 unsigned char staged_status, const char *relpath,
4700 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
4701 struct got_object_id *commit_id, int dirfd, const char *de_name)
4703 struct collect_commitables_arg *a = arg;
4704 const struct got_error *err = NULL;
4705 struct got_commitable *ct = NULL;
4706 struct got_pathlist_entry *new = NULL;
4707 char *parent_path = NULL, *path = NULL;
4708 struct stat sb;
4710 if (a->have_staged_files) {
4711 if (staged_status != GOT_STATUS_MODIFY &&
4712 staged_status != GOT_STATUS_ADD &&
4713 staged_status != GOT_STATUS_DELETE)
4714 return NULL;
4715 } else {
4716 if (status == GOT_STATUS_CONFLICT)
4717 return got_error(GOT_ERR_COMMIT_CONFLICT);
4719 if (status != GOT_STATUS_MODIFY &&
4720 status != GOT_STATUS_MODE_CHANGE &&
4721 status != GOT_STATUS_ADD &&
4722 status != GOT_STATUS_DELETE)
4723 return NULL;
4726 if (asprintf(&path, "/%s", relpath) == -1) {
4727 err = got_error_from_errno("asprintf");
4728 goto done;
4730 if (strcmp(path, "/") == 0) {
4731 parent_path = strdup("");
4732 if (parent_path == NULL)
4733 return got_error_from_errno("strdup");
4734 } else {
4735 err = got_path_dirname(&parent_path, path);
4736 if (err)
4737 return err;
4740 ct = calloc(1, sizeof(*ct));
4741 if (ct == NULL) {
4742 err = got_error_from_errno("calloc");
4743 goto done;
4746 if (asprintf(&ct->ondisk_path, "%s/%s", a->worktree->root_path,
4747 relpath) == -1) {
4748 err = got_error_from_errno("asprintf");
4749 goto done;
4752 if (staged_status == GOT_STATUS_ADD ||
4753 staged_status == GOT_STATUS_MODIFY) {
4754 struct got_fileindex_entry *ie;
4755 ie = got_fileindex_entry_get(a->fileindex, path, strlen(path));
4756 switch (got_fileindex_entry_staged_filetype_get(ie)) {
4757 case GOT_FILEIDX_MODE_REGULAR_FILE:
4758 case GOT_FILEIDX_MODE_BAD_SYMLINK:
4759 ct->mode = S_IFREG;
4760 break;
4761 case GOT_FILEIDX_MODE_SYMLINK:
4762 ct->mode = S_IFLNK;
4763 break;
4764 default:
4765 err = got_error_path(path, GOT_ERR_BAD_FILETYPE);
4766 goto done;
4768 ct->mode |= got_fileindex_entry_perms_get(ie);
4769 } else if (status != GOT_STATUS_DELETE &&
4770 staged_status != GOT_STATUS_DELETE) {
4771 if (dirfd != -1) {
4772 if (fstatat(dirfd, de_name, &sb,
4773 AT_SYMLINK_NOFOLLOW) == -1) {
4774 err = got_error_from_errno2("fstatat",
4775 ct->ondisk_path);
4776 goto done;
4778 } else if (lstat(ct->ondisk_path, &sb) == -1) {
4779 err = got_error_from_errno2("lstat", ct->ondisk_path);
4780 goto done;
4782 ct->mode = sb.st_mode;
4785 if (asprintf(&ct->in_repo_path, "%s%s%s", a->worktree->path_prefix,
4786 got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/",
4787 relpath) == -1) {
4788 err = got_error_from_errno("asprintf");
4789 goto done;
4792 if (S_ISLNK(ct->mode) && staged_status == GOT_STATUS_NO_CHANGE &&
4793 status == GOT_STATUS_ADD && !a->allow_bad_symlinks) {
4794 int is_bad_symlink;
4795 char target_path[PATH_MAX];
4796 ssize_t target_len;
4797 target_len = readlink(ct->ondisk_path, target_path,
4798 sizeof(target_path));
4799 if (target_len == -1) {
4800 err = got_error_from_errno2("readlink",
4801 ct->ondisk_path);
4802 goto done;
4804 err = is_bad_symlink_target(&is_bad_symlink, target_path,
4805 target_len, ct->ondisk_path, a->worktree->root_path);
4806 if (err)
4807 goto done;
4808 if (is_bad_symlink) {
4809 err = got_error_path(ct->ondisk_path,
4810 GOT_ERR_BAD_SYMLINK);
4811 goto done;
4816 ct->status = status;
4817 ct->staged_status = staged_status;
4818 ct->blob_id = NULL; /* will be filled in when blob gets created */
4819 if (ct->status != GOT_STATUS_ADD &&
4820 ct->staged_status != GOT_STATUS_ADD) {
4821 ct->base_blob_id = got_object_id_dup(blob_id);
4822 if (ct->base_blob_id == NULL) {
4823 err = got_error_from_errno("got_object_id_dup");
4824 goto done;
4826 ct->base_commit_id = got_object_id_dup(commit_id);
4827 if (ct->base_commit_id == NULL) {
4828 err = got_error_from_errno("got_object_id_dup");
4829 goto done;
4832 if (ct->staged_status == GOT_STATUS_ADD ||
4833 ct->staged_status == GOT_STATUS_MODIFY) {
4834 ct->staged_blob_id = got_object_id_dup(staged_blob_id);
4835 if (ct->staged_blob_id == NULL) {
4836 err = got_error_from_errno("got_object_id_dup");
4837 goto done;
4840 ct->path = strdup(path);
4841 if (ct->path == NULL) {
4842 err = got_error_from_errno("strdup");
4843 goto done;
4845 err = got_pathlist_insert(&new, a->commitable_paths, ct->path, ct);
4846 done:
4847 if (ct && (err || new == NULL))
4848 free_commitable(ct);
4849 free(parent_path);
4850 free(path);
4851 return err;
4854 static const struct got_error *write_tree(struct got_object_id **, int *,
4855 struct got_tree_object *, const char *, struct got_pathlist_head *,
4856 got_worktree_status_cb status_cb, void *status_arg,
4857 struct got_repository *);
4859 static const struct got_error *
4860 write_subtree(struct got_object_id **new_subtree_id, int *nentries,
4861 struct got_tree_entry *te, const char *parent_path,
4862 struct got_pathlist_head *commitable_paths,
4863 got_worktree_status_cb status_cb, void *status_arg,
4864 struct got_repository *repo)
4866 const struct got_error *err = NULL;
4867 struct got_tree_object *subtree;
4868 char *subpath;
4870 if (asprintf(&subpath, "%s%s%s", parent_path,
4871 got_path_is_root_dir(parent_path) ? "" : "/", te->name) == -1)
4872 return got_error_from_errno("asprintf");
4874 err = got_object_open_as_tree(&subtree, repo, &te->id);
4875 if (err)
4876 return err;
4878 err = write_tree(new_subtree_id, nentries, subtree, subpath,
4879 commitable_paths, status_cb, status_arg, repo);
4880 got_object_tree_close(subtree);
4881 free(subpath);
4882 return err;
4885 static const struct got_error *
4886 match_ct_parent_path(int *match, struct got_commitable *ct, const char *path)
4888 const struct got_error *err = NULL;
4889 char *ct_parent_path = NULL;
4891 *match = 0;
4893 if (strchr(ct->in_repo_path, '/') == NULL) {
4894 *match = got_path_is_root_dir(path);
4895 return NULL;
4898 err = got_path_dirname(&ct_parent_path, ct->in_repo_path);
4899 if (err)
4900 return err;
4901 *match = (strcmp(path, ct_parent_path) == 0);
4902 free(ct_parent_path);
4903 return err;
4906 static mode_t
4907 get_ct_file_mode(struct got_commitable *ct)
4909 if (S_ISLNK(ct->mode))
4910 return S_IFLNK;
4912 return S_IFREG | (ct->mode & ((S_IRWXU | S_IRWXG | S_IRWXO)));
4915 static const struct got_error *
4916 alloc_modified_blob_tree_entry(struct got_tree_entry **new_te,
4917 struct got_tree_entry *te, struct got_commitable *ct)
4919 const struct got_error *err = NULL;
4921 *new_te = NULL;
4923 err = got_object_tree_entry_dup(new_te, te);
4924 if (err)
4925 goto done;
4927 (*new_te)->mode = get_ct_file_mode(ct);
4929 if (ct->staged_status == GOT_STATUS_MODIFY)
4930 memcpy(&(*new_te)->id, ct->staged_blob_id,
4931 sizeof((*new_te)->id));
4932 else
4933 memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id));
4934 done:
4935 if (err && *new_te) {
4936 free(*new_te);
4937 *new_te = NULL;
4939 return err;
4942 static const struct got_error *
4943 alloc_added_blob_tree_entry(struct got_tree_entry **new_te,
4944 struct got_commitable *ct)
4946 const struct got_error *err = NULL;
4947 char *ct_name = NULL;
4949 *new_te = NULL;
4951 *new_te = calloc(1, sizeof(**new_te));
4952 if (*new_te == NULL)
4953 return got_error_from_errno("calloc");
4955 err = got_path_basename(&ct_name, ct->path);
4956 if (err)
4957 goto done;
4958 if (strlcpy((*new_te)->name, ct_name, sizeof((*new_te)->name)) >=
4959 sizeof((*new_te)->name)) {
4960 err = got_error(GOT_ERR_NO_SPACE);
4961 goto done;
4964 (*new_te)->mode = get_ct_file_mode(ct);
4966 if (ct->staged_status == GOT_STATUS_ADD)
4967 memcpy(&(*new_te)->id, ct->staged_blob_id,
4968 sizeof((*new_te)->id));
4969 else
4970 memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id));
4971 done:
4972 free(ct_name);
4973 if (err && *new_te) {
4974 free(*new_te);
4975 *new_te = NULL;
4977 return err;
4980 static const struct got_error *
4981 insert_tree_entry(struct got_tree_entry *new_te,
4982 struct got_pathlist_head *paths)
4984 const struct got_error *err = NULL;
4985 struct got_pathlist_entry *new_pe;
4987 err = got_pathlist_insert(&new_pe, paths, new_te->name, new_te);
4988 if (err)
4989 return err;
4990 if (new_pe == NULL)
4991 return got_error(GOT_ERR_TREE_DUP_ENTRY);
4992 return NULL;
4995 static const struct got_error *
4996 report_ct_status(struct got_commitable *ct,
4997 got_worktree_status_cb status_cb, void *status_arg)
4999 const char *ct_path = ct->path;
5000 unsigned char status;
5002 while (ct_path[0] == '/')
5003 ct_path++;
5005 if (ct->staged_status != GOT_STATUS_NO_CHANGE)
5006 status = ct->staged_status;
5007 else
5008 status = ct->status;
5010 return (*status_cb)(status_arg, status, GOT_STATUS_NO_CHANGE,
5011 ct_path, ct->blob_id, NULL, NULL, -1, NULL);
5014 static const struct got_error *
5015 match_modified_subtree(int *modified, struct got_tree_entry *te,
5016 const char *base_tree_path, struct got_pathlist_head *commitable_paths)
5018 const struct got_error *err = NULL;
5019 struct got_pathlist_entry *pe;
5020 char *te_path;
5022 *modified = 0;
5024 if (asprintf(&te_path, "%s%s%s", base_tree_path,
5025 got_path_is_root_dir(base_tree_path) ? "" : "/",
5026 te->name) == -1)
5027 return got_error_from_errno("asprintf");
5029 TAILQ_FOREACH(pe, commitable_paths, entry) {
5030 struct got_commitable *ct = pe->data;
5031 *modified = got_path_is_child(ct->in_repo_path, te_path,
5032 strlen(te_path));
5033 if (*modified)
5034 break;
5037 free(te_path);
5038 return err;
5041 static const struct got_error *
5042 match_deleted_or_modified_ct(struct got_commitable **ctp,
5043 struct got_tree_entry *te, const char *base_tree_path,
5044 struct got_pathlist_head *commitable_paths)
5046 const struct got_error *err = NULL;
5047 struct got_pathlist_entry *pe;
5049 *ctp = NULL;
5051 TAILQ_FOREACH(pe, commitable_paths, entry) {
5052 struct got_commitable *ct = pe->data;
5053 char *ct_name = NULL;
5054 int path_matches;
5056 if (ct->staged_status == GOT_STATUS_NO_CHANGE) {
5057 if (ct->status != GOT_STATUS_MODIFY &&
5058 ct->status != GOT_STATUS_MODE_CHANGE &&
5059 ct->status != GOT_STATUS_DELETE)
5060 continue;
5061 } else {
5062 if (ct->staged_status != GOT_STATUS_MODIFY &&
5063 ct->staged_status != GOT_STATUS_DELETE)
5064 continue;
5067 if (got_object_id_cmp(ct->base_blob_id, &te->id) != 0)
5068 continue;
5070 err = match_ct_parent_path(&path_matches, ct, base_tree_path);
5071 if (err)
5072 return err;
5073 if (!path_matches)
5074 continue;
5076 err = got_path_basename(&ct_name, pe->path);
5077 if (err)
5078 return err;
5080 if (strcmp(te->name, ct_name) != 0) {
5081 free(ct_name);
5082 continue;
5084 free(ct_name);
5086 *ctp = ct;
5087 break;
5090 return err;
5093 static const struct got_error *
5094 make_subtree_for_added_blob(struct got_tree_entry **new_tep,
5095 const char *child_path, const char *path_base_tree,
5096 struct got_pathlist_head *commitable_paths,
5097 got_worktree_status_cb status_cb, void *status_arg,
5098 struct got_repository *repo)
5100 const struct got_error *err = NULL;
5101 struct got_tree_entry *new_te;
5102 char *subtree_path;
5103 struct got_object_id *id = NULL;
5104 int nentries;
5106 *new_tep = NULL;
5108 if (asprintf(&subtree_path, "%s%s%s", path_base_tree,
5109 got_path_is_root_dir(path_base_tree) ? "" : "/",
5110 child_path) == -1)
5111 return got_error_from_errno("asprintf");
5113 new_te = calloc(1, sizeof(*new_te));
5114 if (new_te == NULL)
5115 return got_error_from_errno("calloc");
5116 new_te->mode = S_IFDIR;
5118 if (strlcpy(new_te->name, child_path, sizeof(new_te->name)) >=
5119 sizeof(new_te->name)) {
5120 err = got_error(GOT_ERR_NO_SPACE);
5121 goto done;
5123 err = write_tree(&id, &nentries, NULL, subtree_path,
5124 commitable_paths, status_cb, status_arg, repo);
5125 if (err) {
5126 free(new_te);
5127 goto done;
5129 memcpy(&new_te->id, id, sizeof(new_te->id));
5130 done:
5131 free(id);
5132 free(subtree_path);
5133 if (err == NULL)
5134 *new_tep = new_te;
5135 return err;
5138 static const struct got_error *
5139 write_tree(struct got_object_id **new_tree_id, int *nentries,
5140 struct got_tree_object *base_tree, const char *path_base_tree,
5141 struct got_pathlist_head *commitable_paths,
5142 got_worktree_status_cb status_cb, void *status_arg,
5143 struct got_repository *repo)
5145 const struct got_error *err = NULL;
5146 struct got_pathlist_head paths;
5147 struct got_tree_entry *te, *new_te = NULL;
5148 struct got_pathlist_entry *pe;
5150 TAILQ_INIT(&paths);
5151 *nentries = 0;
5153 /* Insert, and recurse into, newly added entries first. */
5154 TAILQ_FOREACH(pe, commitable_paths, entry) {
5155 struct got_commitable *ct = pe->data;
5156 char *child_path = NULL, *slash;
5158 if ((ct->status != GOT_STATUS_ADD &&
5159 ct->staged_status != GOT_STATUS_ADD) ||
5160 (ct->flags & GOT_COMMITABLE_ADDED))
5161 continue;
5163 if (!got_path_is_child(ct->in_repo_path, path_base_tree,
5164 strlen(path_base_tree)))
5165 continue;
5167 err = got_path_skip_common_ancestor(&child_path, path_base_tree,
5168 ct->in_repo_path);
5169 if (err)
5170 goto done;
5172 slash = strchr(child_path, '/');
5173 if (slash == NULL) {
5174 err = alloc_added_blob_tree_entry(&new_te, ct);
5175 if (err)
5176 goto done;
5177 err = report_ct_status(ct, status_cb, status_arg);
5178 if (err)
5179 goto done;
5180 ct->flags |= GOT_COMMITABLE_ADDED;
5181 err = insert_tree_entry(new_te, &paths);
5182 if (err)
5183 goto done;
5184 (*nentries)++;
5185 } else {
5186 *slash = '\0'; /* trim trailing path components */
5187 if (base_tree == NULL ||
5188 got_object_tree_find_entry(base_tree, child_path)
5189 == NULL) {
5190 err = make_subtree_for_added_blob(&new_te,
5191 child_path, path_base_tree,
5192 commitable_paths, status_cb, status_arg,
5193 repo);
5194 if (err)
5195 goto done;
5196 err = insert_tree_entry(new_te, &paths);
5197 if (err)
5198 goto done;
5199 (*nentries)++;
5204 if (base_tree) {
5205 int i, nbase_entries;
5206 /* Handle modified and deleted entries. */
5207 nbase_entries = got_object_tree_get_nentries(base_tree);
5208 for (i = 0; i < nbase_entries; i++) {
5209 struct got_commitable *ct = NULL;
5211 te = got_object_tree_get_entry(base_tree, i);
5212 if (got_object_tree_entry_is_submodule(te)) {
5213 /* Entry is a submodule; just copy it. */
5214 err = got_object_tree_entry_dup(&new_te, te);
5215 if (err)
5216 goto done;
5217 err = insert_tree_entry(new_te, &paths);
5218 if (err)
5219 goto done;
5220 (*nentries)++;
5221 continue;
5224 if (S_ISDIR(te->mode)) {
5225 int modified;
5226 err = got_object_tree_entry_dup(&new_te, te);
5227 if (err)
5228 goto done;
5229 err = match_modified_subtree(&modified, te,
5230 path_base_tree, commitable_paths);
5231 if (err)
5232 goto done;
5233 /* Avoid recursion into unmodified subtrees. */
5234 if (modified) {
5235 struct got_object_id *new_id;
5236 int nsubentries;
5237 err = write_subtree(&new_id,
5238 &nsubentries, te,
5239 path_base_tree, commitable_paths,
5240 status_cb, status_arg, repo);
5241 if (err)
5242 goto done;
5243 if (nsubentries == 0) {
5244 /* All entries were deleted. */
5245 free(new_id);
5246 continue;
5248 memcpy(&new_te->id, new_id,
5249 sizeof(new_te->id));
5250 free(new_id);
5252 err = insert_tree_entry(new_te, &paths);
5253 if (err)
5254 goto done;
5255 (*nentries)++;
5256 continue;
5259 err = match_deleted_or_modified_ct(&ct, te,
5260 path_base_tree, commitable_paths);
5261 if (err)
5262 goto done;
5263 if (ct) {
5264 /* NB: Deleted entries get dropped here. */
5265 if (ct->status == GOT_STATUS_MODIFY ||
5266 ct->status == GOT_STATUS_MODE_CHANGE ||
5267 ct->staged_status == GOT_STATUS_MODIFY) {
5268 err = alloc_modified_blob_tree_entry(
5269 &new_te, te, ct);
5270 if (err)
5271 goto done;
5272 err = insert_tree_entry(new_te, &paths);
5273 if (err)
5274 goto done;
5275 (*nentries)++;
5277 err = report_ct_status(ct, status_cb,
5278 status_arg);
5279 if (err)
5280 goto done;
5281 } else {
5282 /* Entry is unchanged; just copy it. */
5283 err = got_object_tree_entry_dup(&new_te, te);
5284 if (err)
5285 goto done;
5286 err = insert_tree_entry(new_te, &paths);
5287 if (err)
5288 goto done;
5289 (*nentries)++;
5294 /* Write new list of entries; deleted entries have been dropped. */
5295 err = got_object_tree_create(new_tree_id, &paths, *nentries, repo);
5296 done:
5297 got_pathlist_free(&paths);
5298 return err;
5301 static const struct got_error *
5302 update_fileindex_after_commit(struct got_worktree *worktree,
5303 struct got_pathlist_head *commitable_paths,
5304 struct got_object_id *new_base_commit_id,
5305 struct got_fileindex *fileindex, int have_staged_files)
5307 const struct got_error *err = NULL;
5308 struct got_pathlist_entry *pe;
5309 char *relpath = NULL;
5311 TAILQ_FOREACH(pe, commitable_paths, entry) {
5312 struct got_fileindex_entry *ie;
5313 struct got_commitable *ct = pe->data;
5315 ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len);
5317 err = got_path_skip_common_ancestor(&relpath,
5318 worktree->root_path, ct->ondisk_path);
5319 if (err)
5320 goto done;
5322 if (ie) {
5323 if (ct->status == GOT_STATUS_DELETE ||
5324 ct->staged_status == GOT_STATUS_DELETE) {
5325 got_fileindex_entry_remove(fileindex, ie);
5326 } else if (ct->staged_status == GOT_STATUS_ADD ||
5327 ct->staged_status == GOT_STATUS_MODIFY) {
5328 got_fileindex_entry_stage_set(ie,
5329 GOT_FILEIDX_STAGE_NONE);
5330 got_fileindex_entry_staged_filetype_set(ie, 0);
5332 err = got_fileindex_entry_update(ie,
5333 worktree->root_fd, relpath,
5334 ct->staged_blob_id->sha1,
5335 new_base_commit_id->sha1,
5336 !have_staged_files);
5337 } else
5338 err = got_fileindex_entry_update(ie,
5339 worktree->root_fd, relpath,
5340 ct->blob_id->sha1,
5341 new_base_commit_id->sha1,
5342 !have_staged_files);
5343 } else {
5344 err = got_fileindex_entry_alloc(&ie, pe->path);
5345 if (err)
5346 goto done;
5347 err = got_fileindex_entry_update(ie,
5348 worktree->root_fd, relpath, ct->blob_id->sha1,
5349 new_base_commit_id->sha1, 1);
5350 if (err) {
5351 got_fileindex_entry_free(ie);
5352 goto done;
5354 err = got_fileindex_entry_add(fileindex, ie);
5355 if (err) {
5356 got_fileindex_entry_free(ie);
5357 goto done;
5360 free(relpath);
5361 relpath = NULL;
5363 done:
5364 free(relpath);
5365 return err;
5369 static const struct got_error *
5370 check_out_of_date(const char *in_repo_path, unsigned char status,
5371 unsigned char staged_status, struct got_object_id *base_blob_id,
5372 struct got_object_id *base_commit_id,
5373 struct got_object_id *head_commit_id, struct got_repository *repo,
5374 int ood_errcode)
5376 const struct got_error *err = NULL;
5377 struct got_object_id *id = NULL;
5379 if (status != GOT_STATUS_ADD && staged_status != GOT_STATUS_ADD) {
5380 /* Trivial case: base commit == head commit */
5381 if (got_object_id_cmp(base_commit_id, head_commit_id) == 0)
5382 return NULL;
5384 * Ensure file content which local changes were based
5385 * on matches file content in the branch head.
5387 err = got_object_id_by_path(&id, repo, head_commit_id,
5388 in_repo_path);
5389 if (err) {
5390 if (err->code == GOT_ERR_NO_TREE_ENTRY)
5391 err = got_error(ood_errcode);
5392 goto done;
5393 } else if (got_object_id_cmp(id, base_blob_id) != 0)
5394 err = got_error(ood_errcode);
5395 } else {
5396 /* Require that added files don't exist in the branch head. */
5397 err = got_object_id_by_path(&id, repo, head_commit_id,
5398 in_repo_path);
5399 if (err && err->code != GOT_ERR_NO_TREE_ENTRY)
5400 goto done;
5401 err = id ? got_error(ood_errcode) : NULL;
5403 done:
5404 free(id);
5405 return err;
5408 const struct got_error *
5409 commit_worktree(struct got_object_id **new_commit_id,
5410 struct got_pathlist_head *commitable_paths,
5411 struct got_object_id *head_commit_id, struct got_worktree *worktree,
5412 const char *author, const char *committer,
5413 got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
5414 got_worktree_status_cb status_cb, void *status_arg,
5415 struct got_repository *repo)
5417 const struct got_error *err = NULL, *unlockerr = NULL;
5418 struct got_pathlist_entry *pe;
5419 const char *head_ref_name = NULL;
5420 struct got_commit_object *head_commit = NULL;
5421 struct got_reference *head_ref2 = NULL;
5422 struct got_object_id *head_commit_id2 = NULL;
5423 struct got_tree_object *head_tree = NULL;
5424 struct got_object_id *new_tree_id = NULL;
5425 int nentries;
5426 struct got_object_id_queue parent_ids;
5427 struct got_object_qid *pid = NULL;
5428 char *logmsg = NULL;
5430 *new_commit_id = NULL;
5432 SIMPLEQ_INIT(&parent_ids);
5434 err = got_object_open_as_commit(&head_commit, repo, head_commit_id);
5435 if (err)
5436 goto done;
5438 err = got_object_open_as_tree(&head_tree, repo, head_commit->tree_id);
5439 if (err)
5440 goto done;
5442 if (commit_msg_cb != NULL) {
5443 err = commit_msg_cb(commitable_paths, &logmsg, commit_arg);
5444 if (err)
5445 goto done;
5448 if (logmsg == NULL || strlen(logmsg) == 0) {
5449 err = got_error(GOT_ERR_COMMIT_MSG_EMPTY);
5450 goto done;
5453 /* Create blobs from added and modified files and record their IDs. */
5454 TAILQ_FOREACH(pe, commitable_paths, entry) {
5455 struct got_commitable *ct = pe->data;
5456 char *ondisk_path;
5458 /* Blobs for staged files already exist. */
5459 if (ct->staged_status == GOT_STATUS_ADD ||
5460 ct->staged_status == GOT_STATUS_MODIFY)
5461 continue;
5463 if (ct->status != GOT_STATUS_ADD &&
5464 ct->status != GOT_STATUS_MODIFY &&
5465 ct->status != GOT_STATUS_MODE_CHANGE)
5466 continue;
5468 if (asprintf(&ondisk_path, "%s/%s",
5469 worktree->root_path, pe->path) == -1) {
5470 err = got_error_from_errno("asprintf");
5471 goto done;
5473 err = got_object_blob_create(&ct->blob_id, ondisk_path, repo);
5474 free(ondisk_path);
5475 if (err)
5476 goto done;
5479 /* Recursively write new tree objects. */
5480 err = write_tree(&new_tree_id, &nentries, head_tree, "/",
5481 commitable_paths, status_cb, status_arg, repo);
5482 if (err)
5483 goto done;
5485 err = got_object_qid_alloc(&pid, worktree->base_commit_id);
5486 if (err)
5487 goto done;
5488 SIMPLEQ_INSERT_TAIL(&parent_ids, pid, entry);
5489 err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids,
5490 1, author, time(NULL), committer, time(NULL), logmsg, repo);
5491 got_object_qid_free(pid);
5492 if (logmsg != NULL)
5493 free(logmsg);
5494 if (err)
5495 goto done;
5497 /* Check if a concurrent commit to our branch has occurred. */
5498 head_ref_name = got_worktree_get_head_ref_name(worktree);
5499 if (head_ref_name == NULL) {
5500 err = got_error_from_errno("got_worktree_get_head_ref_name");
5501 goto done;
5503 /* Lock the reference here to prevent concurrent modification. */
5504 err = got_ref_open(&head_ref2, repo, head_ref_name, 1);
5505 if (err)
5506 goto done;
5507 err = got_ref_resolve(&head_commit_id2, repo, head_ref2);
5508 if (err)
5509 goto done;
5510 if (got_object_id_cmp(head_commit_id, head_commit_id2) != 0) {
5511 err = got_error(GOT_ERR_COMMIT_HEAD_CHANGED);
5512 goto done;
5514 /* Update branch head in repository. */
5515 err = got_ref_change_ref(head_ref2, *new_commit_id);
5516 if (err)
5517 goto done;
5518 err = got_ref_write(head_ref2, repo);
5519 if (err)
5520 goto done;
5522 err = got_worktree_set_base_commit_id(worktree, repo, *new_commit_id);
5523 if (err)
5524 goto done;
5526 err = ref_base_commit(worktree, repo);
5527 if (err)
5528 goto done;
5529 done:
5530 if (head_tree)
5531 got_object_tree_close(head_tree);
5532 if (head_commit)
5533 got_object_commit_close(head_commit);
5534 free(head_commit_id2);
5535 if (head_ref2) {
5536 unlockerr = got_ref_unlock(head_ref2);
5537 if (unlockerr && err == NULL)
5538 err = unlockerr;
5539 got_ref_close(head_ref2);
5541 return err;
5544 static const struct got_error *
5545 check_path_is_commitable(const char *path,
5546 struct got_pathlist_head *commitable_paths)
5548 struct got_pathlist_entry *cpe = NULL;
5549 size_t path_len = strlen(path);
5551 TAILQ_FOREACH(cpe, commitable_paths, entry) {
5552 struct got_commitable *ct = cpe->data;
5553 const char *ct_path = ct->path;
5555 while (ct_path[0] == '/')
5556 ct_path++;
5558 if (strcmp(path, ct_path) == 0 ||
5559 got_path_is_child(ct_path, path, path_len))
5560 break;
5563 if (cpe == NULL)
5564 return got_error_path(path, GOT_ERR_BAD_PATH);
5566 return NULL;
5569 static const struct got_error *
5570 check_staged_file(void *arg, struct got_fileindex_entry *ie)
5572 int *have_staged_files = arg;
5574 if (got_fileindex_entry_stage_get(ie) != GOT_FILEIDX_STAGE_NONE) {
5575 *have_staged_files = 1;
5576 return got_error(GOT_ERR_CANCELLED);
5579 return NULL;
5582 static const struct got_error *
5583 check_non_staged_files(struct got_fileindex *fileindex,
5584 struct got_pathlist_head *paths)
5586 struct got_pathlist_entry *pe;
5587 struct got_fileindex_entry *ie;
5589 TAILQ_FOREACH(pe, paths, entry) {
5590 if (pe->path[0] == '\0')
5591 continue;
5592 ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len);
5593 if (ie == NULL)
5594 return got_error_path(pe->path, GOT_ERR_BAD_PATH);
5595 if (got_fileindex_entry_stage_get(ie) == GOT_FILEIDX_STAGE_NONE)
5596 return got_error_path(pe->path,
5597 GOT_ERR_FILE_NOT_STAGED);
5600 return NULL;
5603 const struct got_error *
5604 got_worktree_commit(struct got_object_id **new_commit_id,
5605 struct got_worktree *worktree, struct got_pathlist_head *paths,
5606 const char *author, const char *committer, int allow_bad_symlinks,
5607 got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
5608 got_worktree_status_cb status_cb, void *status_arg,
5609 struct got_repository *repo)
5611 const struct got_error *err = NULL, *unlockerr = NULL, *sync_err;
5612 struct got_fileindex *fileindex = NULL;
5613 char *fileindex_path = NULL;
5614 struct got_pathlist_head commitable_paths;
5615 struct collect_commitables_arg cc_arg;
5616 struct got_pathlist_entry *pe;
5617 struct got_reference *head_ref = NULL;
5618 struct got_object_id *head_commit_id = NULL;
5619 int have_staged_files = 0;
5621 *new_commit_id = NULL;
5623 TAILQ_INIT(&commitable_paths);
5625 err = lock_worktree(worktree, LOCK_EX);
5626 if (err)
5627 goto done;
5629 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
5630 if (err)
5631 goto done;
5633 err = got_ref_resolve(&head_commit_id, repo, head_ref);
5634 if (err)
5635 goto done;
5637 err = open_fileindex(&fileindex, &fileindex_path, worktree);
5638 if (err)
5639 goto done;
5641 err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file,
5642 &have_staged_files);
5643 if (err && err->code != GOT_ERR_CANCELLED)
5644 goto done;
5645 if (have_staged_files) {
5646 err = check_non_staged_files(fileindex, paths);
5647 if (err)
5648 goto done;
5651 cc_arg.commitable_paths = &commitable_paths;
5652 cc_arg.worktree = worktree;
5653 cc_arg.fileindex = fileindex;
5654 cc_arg.repo = repo;
5655 cc_arg.have_staged_files = have_staged_files;
5656 cc_arg.allow_bad_symlinks = allow_bad_symlinks;
5657 TAILQ_FOREACH(pe, paths, entry) {
5658 err = worktree_status(worktree, pe->path, fileindex, repo,
5659 collect_commitables, &cc_arg, NULL, NULL, 0, 0);
5660 if (err)
5661 goto done;
5664 if (TAILQ_EMPTY(&commitable_paths)) {
5665 err = got_error(GOT_ERR_COMMIT_NO_CHANGES);
5666 goto done;
5669 TAILQ_FOREACH(pe, paths, entry) {
5670 err = check_path_is_commitable(pe->path, &commitable_paths);
5671 if (err)
5672 goto done;
5675 TAILQ_FOREACH(pe, &commitable_paths, entry) {
5676 struct got_commitable *ct = pe->data;
5677 const char *ct_path = ct->in_repo_path;
5679 while (ct_path[0] == '/')
5680 ct_path++;
5681 err = check_out_of_date(ct_path, ct->status,
5682 ct->staged_status, ct->base_blob_id, ct->base_commit_id,
5683 head_commit_id, repo, GOT_ERR_COMMIT_OUT_OF_DATE);
5684 if (err)
5685 goto done;
5689 err = commit_worktree(new_commit_id, &commitable_paths,
5690 head_commit_id, worktree, author, committer,
5691 commit_msg_cb, commit_arg, status_cb, status_arg, repo);
5692 if (err)
5693 goto done;
5695 err = update_fileindex_after_commit(worktree, &commitable_paths,
5696 *new_commit_id, fileindex, have_staged_files);
5697 sync_err = sync_fileindex(fileindex, fileindex_path);
5698 if (sync_err && err == NULL)
5699 err = sync_err;
5700 done:
5701 if (fileindex)
5702 got_fileindex_free(fileindex);
5703 free(fileindex_path);
5704 unlockerr = lock_worktree(worktree, LOCK_SH);
5705 if (unlockerr && err == NULL)
5706 err = unlockerr;
5707 TAILQ_FOREACH(pe, &commitable_paths, entry) {
5708 struct got_commitable *ct = pe->data;
5709 free_commitable(ct);
5711 got_pathlist_free(&commitable_paths);
5712 return err;
5715 const char *
5716 got_commitable_get_path(struct got_commitable *ct)
5718 return ct->path;
5721 unsigned int
5722 got_commitable_get_status(struct got_commitable *ct)
5724 return ct->status;
5727 struct check_rebase_ok_arg {
5728 struct got_worktree *worktree;
5729 struct got_repository *repo;
5732 static const struct got_error *
5733 check_rebase_ok(void *arg, struct got_fileindex_entry *ie)
5735 const struct got_error *err = NULL;
5736 struct check_rebase_ok_arg *a = arg;
5737 unsigned char status;
5738 struct stat sb;
5739 char *ondisk_path;
5741 /* Reject rebase of a work tree with mixed base commits. */
5742 if (memcmp(ie->commit_sha1, a->worktree->base_commit_id->sha1,
5743 SHA1_DIGEST_LENGTH))
5744 return got_error(GOT_ERR_MIXED_COMMITS);
5746 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path)
5747 == -1)
5748 return got_error_from_errno("asprintf");
5750 /* Reject rebase of a work tree with modified or staged files. */
5751 err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
5752 free(ondisk_path);
5753 if (err)
5754 return err;
5756 if (status != GOT_STATUS_NO_CHANGE)
5757 return got_error(GOT_ERR_MODIFIED);
5758 if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE)
5759 return got_error_path(ie->path, GOT_ERR_FILE_STAGED);
5761 return NULL;
5764 const struct got_error *
5765 got_worktree_rebase_prepare(struct got_reference **new_base_branch_ref,
5766 struct got_reference **tmp_branch, struct got_fileindex **fileindex,
5767 struct got_worktree *worktree, struct got_reference *branch,
5768 struct got_repository *repo)
5770 const struct got_error *err = NULL;
5771 char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL;
5772 char *branch_ref_name = NULL;
5773 char *fileindex_path = NULL;
5774 struct check_rebase_ok_arg ok_arg;
5775 struct got_reference *wt_branch = NULL, *branch_ref = NULL;
5776 struct got_object_id *wt_branch_tip = NULL;
5778 *new_base_branch_ref = NULL;
5779 *tmp_branch = NULL;
5780 *fileindex = NULL;
5782 err = lock_worktree(worktree, LOCK_EX);
5783 if (err)
5784 return err;
5786 err = open_fileindex(fileindex, &fileindex_path, worktree);
5787 if (err)
5788 goto done;
5790 ok_arg.worktree = worktree;
5791 ok_arg.repo = repo;
5792 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
5793 &ok_arg);
5794 if (err)
5795 goto done;
5797 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
5798 if (err)
5799 goto done;
5801 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
5802 if (err)
5803 goto done;
5805 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
5806 if (err)
5807 goto done;
5809 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
5810 0);
5811 if (err)
5812 goto done;
5814 err = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
5815 if (err)
5816 goto done;
5817 if (got_object_id_cmp(worktree->base_commit_id, wt_branch_tip) != 0) {
5818 err = got_error(GOT_ERR_REBASE_OUT_OF_DATE);
5819 goto done;
5822 err = got_ref_alloc_symref(new_base_branch_ref,
5823 new_base_branch_ref_name, wt_branch);
5824 if (err)
5825 goto done;
5826 err = got_ref_write(*new_base_branch_ref, repo);
5827 if (err)
5828 goto done;
5830 /* TODO Lock original branch's ref while rebasing? */
5832 err = got_ref_alloc_symref(&branch_ref, branch_ref_name, branch);
5833 if (err)
5834 goto done;
5836 err = got_ref_write(branch_ref, repo);
5837 if (err)
5838 goto done;
5840 err = got_ref_alloc(tmp_branch, tmp_branch_name,
5841 worktree->base_commit_id);
5842 if (err)
5843 goto done;
5844 err = got_ref_write(*tmp_branch, repo);
5845 if (err)
5846 goto done;
5848 err = got_worktree_set_head_ref(worktree, *tmp_branch);
5849 if (err)
5850 goto done;
5851 done:
5852 free(fileindex_path);
5853 free(tmp_branch_name);
5854 free(new_base_branch_ref_name);
5855 free(branch_ref_name);
5856 if (branch_ref)
5857 got_ref_close(branch_ref);
5858 if (wt_branch)
5859 got_ref_close(wt_branch);
5860 free(wt_branch_tip);
5861 if (err) {
5862 if (*new_base_branch_ref) {
5863 got_ref_close(*new_base_branch_ref);
5864 *new_base_branch_ref = NULL;
5866 if (*tmp_branch) {
5867 got_ref_close(*tmp_branch);
5868 *tmp_branch = NULL;
5870 if (*fileindex) {
5871 got_fileindex_free(*fileindex);
5872 *fileindex = NULL;
5874 lock_worktree(worktree, LOCK_SH);
5876 return err;
5879 const struct got_error *
5880 got_worktree_rebase_continue(struct got_object_id **commit_id,
5881 struct got_reference **new_base_branch, struct got_reference **tmp_branch,
5882 struct got_reference **branch, struct got_fileindex **fileindex,
5883 struct got_worktree *worktree, struct got_repository *repo)
5885 const struct got_error *err;
5886 char *commit_ref_name = NULL, *new_base_branch_ref_name = NULL;
5887 char *tmp_branch_name = NULL, *branch_ref_name = NULL;
5888 struct got_reference *commit_ref = NULL, *branch_ref = NULL;
5889 char *fileindex_path = NULL;
5890 int have_staged_files = 0;
5892 *commit_id = NULL;
5893 *new_base_branch = NULL;
5894 *tmp_branch = NULL;
5895 *branch = NULL;
5896 *fileindex = NULL;
5898 err = lock_worktree(worktree, LOCK_EX);
5899 if (err)
5900 return err;
5902 err = open_fileindex(fileindex, &fileindex_path, worktree);
5903 if (err)
5904 goto done;
5906 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
5907 &have_staged_files);
5908 if (err && err->code != GOT_ERR_CANCELLED)
5909 goto done;
5910 if (have_staged_files) {
5911 err = got_error(GOT_ERR_STAGED_PATHS);
5912 goto done;
5915 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
5916 if (err)
5917 goto done;
5919 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
5920 if (err)
5921 goto done;
5923 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
5924 if (err)
5925 goto done;
5927 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
5928 if (err)
5929 goto done;
5931 err = got_ref_open(&branch_ref, repo, branch_ref_name, 0);
5932 if (err)
5933 goto done;
5935 err = got_ref_open(branch, repo,
5936 got_ref_get_symref_target(branch_ref), 0);
5937 if (err)
5938 goto done;
5940 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
5941 if (err)
5942 goto done;
5944 err = got_ref_resolve(commit_id, repo, commit_ref);
5945 if (err)
5946 goto done;
5948 err = got_ref_open(new_base_branch, repo,
5949 new_base_branch_ref_name, 0);
5950 if (err)
5951 goto done;
5953 err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0);
5954 if (err)
5955 goto done;
5956 done:
5957 free(commit_ref_name);
5958 free(branch_ref_name);
5959 free(fileindex_path);
5960 if (commit_ref)
5961 got_ref_close(commit_ref);
5962 if (branch_ref)
5963 got_ref_close(branch_ref);
5964 if (err) {
5965 free(*commit_id);
5966 *commit_id = NULL;
5967 if (*tmp_branch) {
5968 got_ref_close(*tmp_branch);
5969 *tmp_branch = NULL;
5971 if (*new_base_branch) {
5972 got_ref_close(*new_base_branch);
5973 *new_base_branch = NULL;
5975 if (*branch) {
5976 got_ref_close(*branch);
5977 *branch = NULL;
5979 if (*fileindex) {
5980 got_fileindex_free(*fileindex);
5981 *fileindex = NULL;
5983 lock_worktree(worktree, LOCK_SH);
5985 return err;
5988 const struct got_error *
5989 got_worktree_rebase_in_progress(int *in_progress, struct got_worktree *worktree)
5991 const struct got_error *err;
5992 char *tmp_branch_name = NULL;
5994 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
5995 if (err)
5996 return err;
5998 *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0);
5999 free(tmp_branch_name);
6000 return NULL;
6003 static const struct got_error *
6004 collect_rebase_commit_msg(struct got_pathlist_head *commitable_paths,
6005 char **logmsg, void *arg)
6007 *logmsg = arg;
6008 return NULL;
6011 static const struct got_error *
6012 rebase_status(void *arg, unsigned char status, unsigned char staged_status,
6013 const char *path, struct got_object_id *blob_id,
6014 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
6015 int dirfd, const char *de_name)
6017 return NULL;
6020 struct collect_merged_paths_arg {
6021 got_worktree_checkout_cb progress_cb;
6022 void *progress_arg;
6023 struct got_pathlist_head *merged_paths;
6026 static const struct got_error *
6027 collect_merged_paths(void *arg, unsigned char status, const char *path)
6029 const struct got_error *err;
6030 struct collect_merged_paths_arg *a = arg;
6031 char *p;
6032 struct got_pathlist_entry *new;
6034 err = (*a->progress_cb)(a->progress_arg, status, path);
6035 if (err)
6036 return err;
6038 if (status != GOT_STATUS_MERGE &&
6039 status != GOT_STATUS_ADD &&
6040 status != GOT_STATUS_DELETE &&
6041 status != GOT_STATUS_CONFLICT)
6042 return NULL;
6044 p = strdup(path);
6045 if (p == NULL)
6046 return got_error_from_errno("strdup");
6048 err = got_pathlist_insert(&new, a->merged_paths, p, NULL);
6049 if (err || new == NULL)
6050 free(p);
6051 return err;
6054 void
6055 got_worktree_rebase_pathlist_free(struct got_pathlist_head *merged_paths)
6057 struct got_pathlist_entry *pe;
6059 TAILQ_FOREACH(pe, merged_paths, entry)
6060 free((char *)pe->path);
6062 got_pathlist_free(merged_paths);
6065 static const struct got_error *
6066 store_commit_id(const char *commit_ref_name, struct got_object_id *commit_id,
6067 int is_rebase, struct got_repository *repo)
6069 const struct got_error *err;
6070 struct got_reference *commit_ref = NULL;
6072 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6073 if (err) {
6074 if (err->code != GOT_ERR_NOT_REF)
6075 goto done;
6076 err = got_ref_alloc(&commit_ref, commit_ref_name, commit_id);
6077 if (err)
6078 goto done;
6079 err = got_ref_write(commit_ref, repo);
6080 if (err)
6081 goto done;
6082 } else if (is_rebase) {
6083 struct got_object_id *stored_id;
6084 int cmp;
6086 err = got_ref_resolve(&stored_id, repo, commit_ref);
6087 if (err)
6088 goto done;
6089 cmp = got_object_id_cmp(commit_id, stored_id);
6090 free(stored_id);
6091 if (cmp != 0) {
6092 err = got_error(GOT_ERR_REBASE_COMMITID);
6093 goto done;
6096 done:
6097 if (commit_ref)
6098 got_ref_close(commit_ref);
6099 return err;
6102 static const struct got_error *
6103 rebase_merge_files(struct got_pathlist_head *merged_paths,
6104 const char *commit_ref_name, struct got_worktree *worktree,
6105 struct got_fileindex *fileindex, struct got_object_id *parent_commit_id,
6106 struct got_object_id *commit_id, struct got_repository *repo,
6107 got_worktree_checkout_cb progress_cb, void *progress_arg,
6108 got_cancel_cb cancel_cb, void *cancel_arg)
6110 const struct got_error *err;
6111 struct got_reference *commit_ref = NULL;
6112 struct collect_merged_paths_arg cmp_arg;
6113 char *fileindex_path;
6115 /* Work tree is locked/unlocked during rebase preparation/teardown. */
6117 err = get_fileindex_path(&fileindex_path, worktree);
6118 if (err)
6119 return err;
6121 cmp_arg.progress_cb = progress_cb;
6122 cmp_arg.progress_arg = progress_arg;
6123 cmp_arg.merged_paths = merged_paths;
6124 err = merge_files(worktree, fileindex, fileindex_path,
6125 parent_commit_id, commit_id, repo, collect_merged_paths,
6126 &cmp_arg, cancel_cb, cancel_arg);
6127 if (commit_ref)
6128 got_ref_close(commit_ref);
6129 return err;
6132 const struct got_error *
6133 got_worktree_rebase_merge_files(struct got_pathlist_head *merged_paths,
6134 struct got_worktree *worktree, struct got_fileindex *fileindex,
6135 struct got_object_id *parent_commit_id, struct got_object_id *commit_id,
6136 struct got_repository *repo,
6137 got_worktree_checkout_cb progress_cb, void *progress_arg,
6138 got_cancel_cb cancel_cb, void *cancel_arg)
6140 const struct got_error *err;
6141 char *commit_ref_name;
6143 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
6144 if (err)
6145 return err;
6147 err = store_commit_id(commit_ref_name, commit_id, 1, repo);
6148 if (err)
6149 goto done;
6151 err = rebase_merge_files(merged_paths, commit_ref_name, worktree,
6152 fileindex, parent_commit_id, commit_id, repo, progress_cb,
6153 progress_arg, cancel_cb, cancel_arg);
6154 done:
6155 free(commit_ref_name);
6156 return err;
6159 const struct got_error *
6160 got_worktree_histedit_merge_files(struct got_pathlist_head *merged_paths,
6161 struct got_worktree *worktree, struct got_fileindex *fileindex,
6162 struct got_object_id *parent_commit_id, struct got_object_id *commit_id,
6163 struct got_repository *repo,
6164 got_worktree_checkout_cb progress_cb, void *progress_arg,
6165 got_cancel_cb cancel_cb, void *cancel_arg)
6167 const struct got_error *err;
6168 char *commit_ref_name;
6170 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
6171 if (err)
6172 return err;
6174 err = store_commit_id(commit_ref_name, commit_id, 0, repo);
6175 if (err)
6176 goto done;
6178 err = rebase_merge_files(merged_paths, commit_ref_name, worktree,
6179 fileindex, parent_commit_id, commit_id, repo, progress_cb,
6180 progress_arg, cancel_cb, cancel_arg);
6181 done:
6182 free(commit_ref_name);
6183 return err;
6186 static const struct got_error *
6187 rebase_commit(struct got_object_id **new_commit_id,
6188 struct got_pathlist_head *merged_paths, struct got_reference *commit_ref,
6189 struct got_worktree *worktree, struct got_fileindex *fileindex,
6190 struct got_reference *tmp_branch, struct got_commit_object *orig_commit,
6191 const char *new_logmsg, struct got_repository *repo)
6193 const struct got_error *err, *sync_err;
6194 struct got_pathlist_head commitable_paths;
6195 struct collect_commitables_arg cc_arg;
6196 char *fileindex_path = NULL;
6197 struct got_reference *head_ref = NULL;
6198 struct got_object_id *head_commit_id = NULL;
6199 char *logmsg = NULL;
6201 TAILQ_INIT(&commitable_paths);
6202 *new_commit_id = NULL;
6204 /* Work tree is locked/unlocked during rebase preparation/teardown. */
6206 err = get_fileindex_path(&fileindex_path, worktree);
6207 if (err)
6208 return err;
6210 cc_arg.commitable_paths = &commitable_paths;
6211 cc_arg.worktree = worktree;
6212 cc_arg.repo = repo;
6213 cc_arg.have_staged_files = 0;
6215 * If possible get the status of individual files directly to
6216 * avoid crawling the entire work tree once per rebased commit.
6217 * TODO: Ideally, merged_paths would contain a list of commitables
6218 * we could use so we could skip worktree_status() entirely.
6220 if (merged_paths) {
6221 struct got_pathlist_entry *pe;
6222 TAILQ_FOREACH(pe, merged_paths, entry) {
6223 err = worktree_status(worktree, pe->path, fileindex,
6224 repo, collect_commitables, &cc_arg, NULL, NULL, 0,
6225 0);
6226 if (err)
6227 goto done;
6229 } else {
6230 err = worktree_status(worktree, "", fileindex, repo,
6231 collect_commitables, &cc_arg, NULL, NULL, 0, 0);
6232 if (err)
6233 goto done;
6236 if (TAILQ_EMPTY(&commitable_paths)) {
6237 /* No-op change; commit will be elided. */
6238 err = got_ref_delete(commit_ref, repo);
6239 if (err)
6240 goto done;
6241 err = got_error(GOT_ERR_COMMIT_NO_CHANGES);
6242 goto done;
6245 err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
6246 if (err)
6247 goto done;
6249 err = got_ref_resolve(&head_commit_id, repo, head_ref);
6250 if (err)
6251 goto done;
6253 if (new_logmsg) {
6254 logmsg = strdup(new_logmsg);
6255 if (logmsg == NULL) {
6256 err = got_error_from_errno("strdup");
6257 goto done;
6259 } else {
6260 err = got_object_commit_get_logmsg(&logmsg, orig_commit);
6261 if (err)
6262 goto done;
6265 /* NB: commit_worktree will call free(logmsg) */
6266 err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id,
6267 worktree, got_object_commit_get_author(orig_commit),
6268 got_object_commit_get_committer(orig_commit),
6269 collect_rebase_commit_msg, logmsg, rebase_status, NULL, repo);
6270 if (err)
6271 goto done;
6273 err = got_ref_change_ref(tmp_branch, *new_commit_id);
6274 if (err)
6275 goto done;
6277 err = got_ref_delete(commit_ref, repo);
6278 if (err)
6279 goto done;
6281 err = update_fileindex_after_commit(worktree, &commitable_paths,
6282 *new_commit_id, fileindex, 0);
6283 sync_err = sync_fileindex(fileindex, fileindex_path);
6284 if (sync_err && err == NULL)
6285 err = sync_err;
6286 done:
6287 free(fileindex_path);
6288 free(head_commit_id);
6289 if (head_ref)
6290 got_ref_close(head_ref);
6291 if (err) {
6292 free(*new_commit_id);
6293 *new_commit_id = NULL;
6295 return err;
6298 const struct got_error *
6299 got_worktree_rebase_commit(struct got_object_id **new_commit_id,
6300 struct got_pathlist_head *merged_paths, struct got_worktree *worktree,
6301 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
6302 struct got_commit_object *orig_commit,
6303 struct got_object_id *orig_commit_id, struct got_repository *repo)
6305 const struct got_error *err;
6306 char *commit_ref_name;
6307 struct got_reference *commit_ref = NULL;
6308 struct got_object_id *commit_id = NULL;
6310 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
6311 if (err)
6312 return err;
6314 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6315 if (err)
6316 goto done;
6317 err = got_ref_resolve(&commit_id, repo, commit_ref);
6318 if (err)
6319 goto done;
6320 if (got_object_id_cmp(commit_id, orig_commit_id) != 0) {
6321 err = got_error(GOT_ERR_REBASE_COMMITID);
6322 goto done;
6325 err = rebase_commit(new_commit_id, merged_paths, commit_ref,
6326 worktree, fileindex, tmp_branch, orig_commit, NULL, repo);
6327 done:
6328 if (commit_ref)
6329 got_ref_close(commit_ref);
6330 free(commit_ref_name);
6331 free(commit_id);
6332 return err;
6335 const struct got_error *
6336 got_worktree_histedit_commit(struct got_object_id **new_commit_id,
6337 struct got_pathlist_head *merged_paths, struct got_worktree *worktree,
6338 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
6339 struct got_commit_object *orig_commit,
6340 struct got_object_id *orig_commit_id, const char *new_logmsg,
6341 struct got_repository *repo)
6343 const struct got_error *err;
6344 char *commit_ref_name;
6345 struct got_reference *commit_ref = NULL;
6347 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
6348 if (err)
6349 return err;
6351 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6352 if (err)
6353 goto done;
6355 err = rebase_commit(new_commit_id, merged_paths, commit_ref,
6356 worktree, fileindex, tmp_branch, orig_commit, new_logmsg, repo);
6357 done:
6358 if (commit_ref)
6359 got_ref_close(commit_ref);
6360 free(commit_ref_name);
6361 return err;
6364 const struct got_error *
6365 got_worktree_rebase_postpone(struct got_worktree *worktree,
6366 struct got_fileindex *fileindex)
6368 if (fileindex)
6369 got_fileindex_free(fileindex);
6370 return lock_worktree(worktree, LOCK_SH);
6373 static const struct got_error *
6374 delete_ref(const char *name, struct got_repository *repo)
6376 const struct got_error *err;
6377 struct got_reference *ref;
6379 err = got_ref_open(&ref, repo, name, 0);
6380 if (err) {
6381 if (err->code == GOT_ERR_NOT_REF)
6382 return NULL;
6383 return err;
6386 err = got_ref_delete(ref, repo);
6387 got_ref_close(ref);
6388 return err;
6391 static const struct got_error *
6392 delete_rebase_refs(struct got_worktree *worktree, struct got_repository *repo)
6394 const struct got_error *err;
6395 char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL;
6396 char *branch_ref_name = NULL, *commit_ref_name = NULL;
6398 err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
6399 if (err)
6400 goto done;
6401 err = delete_ref(tmp_branch_name, repo);
6402 if (err)
6403 goto done;
6405 err = get_newbase_symref_name(&new_base_branch_ref_name, worktree);
6406 if (err)
6407 goto done;
6408 err = delete_ref(new_base_branch_ref_name, repo);
6409 if (err)
6410 goto done;
6412 err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
6413 if (err)
6414 goto done;
6415 err = delete_ref(branch_ref_name, repo);
6416 if (err)
6417 goto done;
6419 err = get_rebase_commit_ref_name(&commit_ref_name, worktree);
6420 if (err)
6421 goto done;
6422 err = delete_ref(commit_ref_name, repo);
6423 if (err)
6424 goto done;
6426 done:
6427 free(tmp_branch_name);
6428 free(new_base_branch_ref_name);
6429 free(branch_ref_name);
6430 free(commit_ref_name);
6431 return err;
6434 const struct got_error *
6435 got_worktree_rebase_complete(struct got_worktree *worktree,
6436 struct got_fileindex *fileindex, struct got_reference *new_base_branch,
6437 struct got_reference *tmp_branch, struct got_reference *rebased_branch,
6438 struct got_repository *repo)
6440 const struct got_error *err, *unlockerr;
6441 struct got_object_id *new_head_commit_id = NULL;
6443 err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch);
6444 if (err)
6445 return err;
6447 err = got_ref_change_ref(rebased_branch, new_head_commit_id);
6448 if (err)
6449 goto done;
6451 err = got_ref_write(rebased_branch, repo);
6452 if (err)
6453 goto done;
6455 err = got_worktree_set_head_ref(worktree, rebased_branch);
6456 if (err)
6457 goto done;
6459 err = delete_rebase_refs(worktree, repo);
6460 done:
6461 if (fileindex)
6462 got_fileindex_free(fileindex);
6463 free(new_head_commit_id);
6464 unlockerr = lock_worktree(worktree, LOCK_SH);
6465 if (unlockerr && err == NULL)
6466 err = unlockerr;
6467 return err;
6470 const struct got_error *
6471 got_worktree_rebase_abort(struct got_worktree *worktree,
6472 struct got_fileindex *fileindex, struct got_repository *repo,
6473 struct got_reference *new_base_branch,
6474 got_worktree_checkout_cb progress_cb, void *progress_arg)
6476 const struct got_error *err, *unlockerr, *sync_err;
6477 struct got_reference *resolved = NULL;
6478 struct got_object_id *commit_id = NULL;
6479 char *fileindex_path = NULL;
6480 struct revert_file_args rfa;
6481 struct got_object_id *tree_id = NULL;
6483 err = lock_worktree(worktree, LOCK_EX);
6484 if (err)
6485 return err;
6487 err = got_ref_open(&resolved, repo,
6488 got_ref_get_symref_target(new_base_branch), 0);
6489 if (err)
6490 goto done;
6492 err = got_worktree_set_head_ref(worktree, resolved);
6493 if (err)
6494 goto done;
6497 * XXX commits to the base branch could have happened while
6498 * we were busy rebasing; should we store the original commit ID
6499 * when rebase begins and read it back here?
6501 err = got_ref_resolve(&commit_id, repo, resolved);
6502 if (err)
6503 goto done;
6505 err = got_worktree_set_base_commit_id(worktree, repo, commit_id);
6506 if (err)
6507 goto done;
6509 err = got_object_id_by_path(&tree_id, repo,
6510 worktree->base_commit_id, worktree->path_prefix);
6511 if (err)
6512 goto done;
6514 err = delete_rebase_refs(worktree, repo);
6515 if (err)
6516 goto done;
6518 err = get_fileindex_path(&fileindex_path, worktree);
6519 if (err)
6520 goto done;
6522 rfa.worktree = worktree;
6523 rfa.fileindex = fileindex;
6524 rfa.progress_cb = progress_cb;
6525 rfa.progress_arg = progress_arg;
6526 rfa.patch_cb = NULL;
6527 rfa.patch_arg = NULL;
6528 rfa.repo = repo;
6529 err = worktree_status(worktree, "", fileindex, repo,
6530 revert_file, &rfa, NULL, NULL, 0, 0);
6531 if (err)
6532 goto sync;
6534 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
6535 repo, progress_cb, progress_arg, NULL, NULL);
6536 sync:
6537 sync_err = sync_fileindex(fileindex, fileindex_path);
6538 if (sync_err && err == NULL)
6539 err = sync_err;
6540 done:
6541 got_ref_close(resolved);
6542 free(tree_id);
6543 free(commit_id);
6544 if (fileindex)
6545 got_fileindex_free(fileindex);
6546 free(fileindex_path);
6548 unlockerr = lock_worktree(worktree, LOCK_SH);
6549 if (unlockerr && err == NULL)
6550 err = unlockerr;
6551 return err;
6554 const struct got_error *
6555 got_worktree_histedit_prepare(struct got_reference **tmp_branch,
6556 struct got_reference **branch_ref, struct got_object_id **base_commit_id,
6557 struct got_fileindex **fileindex, struct got_worktree *worktree,
6558 struct got_repository *repo)
6560 const struct got_error *err = NULL;
6561 char *tmp_branch_name = NULL;
6562 char *branch_ref_name = NULL;
6563 char *base_commit_ref_name = NULL;
6564 char *fileindex_path = NULL;
6565 struct check_rebase_ok_arg ok_arg;
6566 struct got_reference *wt_branch = NULL;
6567 struct got_reference *base_commit_ref = NULL;
6569 *tmp_branch = NULL;
6570 *branch_ref = NULL;
6571 *base_commit_id = NULL;
6572 *fileindex = NULL;
6574 err = lock_worktree(worktree, LOCK_EX);
6575 if (err)
6576 return err;
6578 err = open_fileindex(fileindex, &fileindex_path, worktree);
6579 if (err)
6580 goto done;
6582 ok_arg.worktree = worktree;
6583 ok_arg.repo = repo;
6584 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
6585 &ok_arg);
6586 if (err)
6587 goto done;
6589 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
6590 if (err)
6591 goto done;
6593 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
6594 if (err)
6595 goto done;
6597 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
6598 worktree);
6599 if (err)
6600 goto done;
6602 err = got_ref_open(&wt_branch, repo, worktree->head_ref_name,
6603 0);
6604 if (err)
6605 goto done;
6607 err = got_ref_alloc_symref(branch_ref, branch_ref_name, wt_branch);
6608 if (err)
6609 goto done;
6611 err = got_ref_write(*branch_ref, repo);
6612 if (err)
6613 goto done;
6615 err = got_ref_alloc(&base_commit_ref, base_commit_ref_name,
6616 worktree->base_commit_id);
6617 if (err)
6618 goto done;
6619 err = got_ref_write(base_commit_ref, repo);
6620 if (err)
6621 goto done;
6622 *base_commit_id = got_object_id_dup(worktree->base_commit_id);
6623 if (*base_commit_id == NULL) {
6624 err = got_error_from_errno("got_object_id_dup");
6625 goto done;
6628 err = got_ref_alloc(tmp_branch, tmp_branch_name,
6629 worktree->base_commit_id);
6630 if (err)
6631 goto done;
6632 err = got_ref_write(*tmp_branch, repo);
6633 if (err)
6634 goto done;
6636 err = got_worktree_set_head_ref(worktree, *tmp_branch);
6637 if (err)
6638 goto done;
6639 done:
6640 free(fileindex_path);
6641 free(tmp_branch_name);
6642 free(branch_ref_name);
6643 free(base_commit_ref_name);
6644 if (wt_branch)
6645 got_ref_close(wt_branch);
6646 if (err) {
6647 if (*branch_ref) {
6648 got_ref_close(*branch_ref);
6649 *branch_ref = NULL;
6651 if (*tmp_branch) {
6652 got_ref_close(*tmp_branch);
6653 *tmp_branch = NULL;
6655 free(*base_commit_id);
6656 if (*fileindex) {
6657 got_fileindex_free(*fileindex);
6658 *fileindex = NULL;
6660 lock_worktree(worktree, LOCK_SH);
6662 return err;
6665 const struct got_error *
6666 got_worktree_histedit_postpone(struct got_worktree *worktree,
6667 struct got_fileindex *fileindex)
6669 if (fileindex)
6670 got_fileindex_free(fileindex);
6671 return lock_worktree(worktree, LOCK_SH);
6674 const struct got_error *
6675 got_worktree_histedit_in_progress(int *in_progress,
6676 struct got_worktree *worktree)
6678 const struct got_error *err;
6679 char *tmp_branch_name = NULL;
6681 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
6682 if (err)
6683 return err;
6685 *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0);
6686 free(tmp_branch_name);
6687 return NULL;
6690 const struct got_error *
6691 got_worktree_histedit_continue(struct got_object_id **commit_id,
6692 struct got_reference **tmp_branch, struct got_reference **branch_ref,
6693 struct got_object_id **base_commit_id, struct got_fileindex **fileindex,
6694 struct got_worktree *worktree, struct got_repository *repo)
6696 const struct got_error *err;
6697 char *commit_ref_name = NULL, *base_commit_ref_name = NULL;
6698 char *tmp_branch_name = NULL, *branch_ref_name = NULL;
6699 struct got_reference *commit_ref = NULL;
6700 struct got_reference *base_commit_ref = NULL;
6701 char *fileindex_path = NULL;
6702 int have_staged_files = 0;
6704 *commit_id = NULL;
6705 *tmp_branch = NULL;
6706 *base_commit_id = NULL;
6707 *fileindex = NULL;
6709 err = lock_worktree(worktree, LOCK_EX);
6710 if (err)
6711 return err;
6713 err = open_fileindex(fileindex, &fileindex_path, worktree);
6714 if (err)
6715 goto done;
6717 err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
6718 &have_staged_files);
6719 if (err && err->code != GOT_ERR_CANCELLED)
6720 goto done;
6721 if (have_staged_files) {
6722 err = got_error(GOT_ERR_STAGED_PATHS);
6723 goto done;
6726 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
6727 if (err)
6728 goto done;
6730 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
6731 if (err)
6732 goto done;
6734 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
6735 if (err)
6736 goto done;
6738 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
6739 worktree);
6740 if (err)
6741 goto done;
6743 err = got_ref_open(branch_ref, repo, branch_ref_name, 0);
6744 if (err)
6745 goto done;
6747 err = got_ref_open(&commit_ref, repo, commit_ref_name, 0);
6748 if (err)
6749 goto done;
6750 err = got_ref_resolve(commit_id, repo, commit_ref);
6751 if (err)
6752 goto done;
6754 err = got_ref_open(&base_commit_ref, repo, base_commit_ref_name, 0);
6755 if (err)
6756 goto done;
6757 err = got_ref_resolve(base_commit_id, repo, base_commit_ref);
6758 if (err)
6759 goto done;
6761 err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0);
6762 if (err)
6763 goto done;
6764 done:
6765 free(commit_ref_name);
6766 free(branch_ref_name);
6767 free(fileindex_path);
6768 if (commit_ref)
6769 got_ref_close(commit_ref);
6770 if (base_commit_ref)
6771 got_ref_close(base_commit_ref);
6772 if (err) {
6773 free(*commit_id);
6774 *commit_id = NULL;
6775 free(*base_commit_id);
6776 *base_commit_id = NULL;
6777 if (*tmp_branch) {
6778 got_ref_close(*tmp_branch);
6779 *tmp_branch = NULL;
6781 if (*fileindex) {
6782 got_fileindex_free(*fileindex);
6783 *fileindex = NULL;
6785 lock_worktree(worktree, LOCK_EX);
6787 return err;
6790 static const struct got_error *
6791 delete_histedit_refs(struct got_worktree *worktree, struct got_repository *repo)
6793 const struct got_error *err;
6794 char *tmp_branch_name = NULL, *base_commit_ref_name = NULL;
6795 char *branch_ref_name = NULL, *commit_ref_name = NULL;
6797 err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
6798 if (err)
6799 goto done;
6800 err = delete_ref(tmp_branch_name, repo);
6801 if (err)
6802 goto done;
6804 err = get_histedit_base_commit_ref_name(&base_commit_ref_name,
6805 worktree);
6806 if (err)
6807 goto done;
6808 err = delete_ref(base_commit_ref_name, repo);
6809 if (err)
6810 goto done;
6812 err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
6813 if (err)
6814 goto done;
6815 err = delete_ref(branch_ref_name, repo);
6816 if (err)
6817 goto done;
6819 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
6820 if (err)
6821 goto done;
6822 err = delete_ref(commit_ref_name, repo);
6823 if (err)
6824 goto done;
6825 done:
6826 free(tmp_branch_name);
6827 free(base_commit_ref_name);
6828 free(branch_ref_name);
6829 free(commit_ref_name);
6830 return err;
6833 const struct got_error *
6834 got_worktree_histedit_abort(struct got_worktree *worktree,
6835 struct got_fileindex *fileindex, struct got_repository *repo,
6836 struct got_reference *branch, struct got_object_id *base_commit_id,
6837 got_worktree_checkout_cb progress_cb, void *progress_arg)
6839 const struct got_error *err, *unlockerr, *sync_err;
6840 struct got_reference *resolved = NULL;
6841 char *fileindex_path = NULL;
6842 struct got_object_id *tree_id = NULL;
6843 struct revert_file_args rfa;
6845 err = lock_worktree(worktree, LOCK_EX);
6846 if (err)
6847 return err;
6849 err = got_ref_open(&resolved, repo,
6850 got_ref_get_symref_target(branch), 0);
6851 if (err)
6852 goto done;
6854 err = got_worktree_set_head_ref(worktree, resolved);
6855 if (err)
6856 goto done;
6858 err = got_worktree_set_base_commit_id(worktree, repo, base_commit_id);
6859 if (err)
6860 goto done;
6862 err = got_object_id_by_path(&tree_id, repo, base_commit_id,
6863 worktree->path_prefix);
6864 if (err)
6865 goto done;
6867 err = delete_histedit_refs(worktree, repo);
6868 if (err)
6869 goto done;
6871 err = get_fileindex_path(&fileindex_path, worktree);
6872 if (err)
6873 goto done;
6875 rfa.worktree = worktree;
6876 rfa.fileindex = fileindex;
6877 rfa.progress_cb = progress_cb;
6878 rfa.progress_arg = progress_arg;
6879 rfa.patch_cb = NULL;
6880 rfa.patch_arg = NULL;
6881 rfa.repo = repo;
6882 err = worktree_status(worktree, "", fileindex, repo,
6883 revert_file, &rfa, NULL, NULL, 0, 0);
6884 if (err)
6885 goto sync;
6887 err = checkout_files(worktree, fileindex, "", tree_id, NULL,
6888 repo, progress_cb, progress_arg, NULL, NULL);
6889 sync:
6890 sync_err = sync_fileindex(fileindex, fileindex_path);
6891 if (sync_err && err == NULL)
6892 err = sync_err;
6893 done:
6894 got_ref_close(resolved);
6895 free(tree_id);
6896 free(fileindex_path);
6898 unlockerr = lock_worktree(worktree, LOCK_SH);
6899 if (unlockerr && err == NULL)
6900 err = unlockerr;
6901 return err;
6904 const struct got_error *
6905 got_worktree_histedit_complete(struct got_worktree *worktree,
6906 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
6907 struct got_reference *edited_branch, struct got_repository *repo)
6909 const struct got_error *err, *unlockerr;
6910 struct got_object_id *new_head_commit_id = NULL;
6911 struct got_reference *resolved = NULL;
6913 err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch);
6914 if (err)
6915 return err;
6917 err = got_ref_open(&resolved, repo,
6918 got_ref_get_symref_target(edited_branch), 0);
6919 if (err)
6920 goto done;
6922 err = got_ref_change_ref(resolved, new_head_commit_id);
6923 if (err)
6924 goto done;
6926 err = got_ref_write(resolved, repo);
6927 if (err)
6928 goto done;
6930 err = got_worktree_set_head_ref(worktree, resolved);
6931 if (err)
6932 goto done;
6934 err = delete_histedit_refs(worktree, repo);
6935 done:
6936 if (fileindex)
6937 got_fileindex_free(fileindex);
6938 free(new_head_commit_id);
6939 unlockerr = lock_worktree(worktree, LOCK_SH);
6940 if (unlockerr && err == NULL)
6941 err = unlockerr;
6942 return err;
6945 const struct got_error *
6946 got_worktree_histedit_skip_commit(struct got_worktree *worktree,
6947 struct got_object_id *commit_id, struct got_repository *repo)
6949 const struct got_error *err;
6950 char *commit_ref_name;
6952 err = get_histedit_commit_ref_name(&commit_ref_name, worktree);
6953 if (err)
6954 return err;
6956 err = store_commit_id(commit_ref_name, commit_id, 0, repo);
6957 if (err)
6958 goto done;
6960 err = delete_ref(commit_ref_name, repo);
6961 done:
6962 free(commit_ref_name);
6963 return err;
6966 const struct got_error *
6967 got_worktree_integrate_prepare(struct got_fileindex **fileindex,
6968 struct got_reference **branch_ref, struct got_reference **base_branch_ref,
6969 struct got_worktree *worktree, const char *refname,
6970 struct got_repository *repo)
6972 const struct got_error *err = NULL;
6973 char *fileindex_path = NULL;
6974 struct check_rebase_ok_arg ok_arg;
6976 *fileindex = NULL;
6977 *branch_ref = NULL;
6978 *base_branch_ref = NULL;
6980 err = lock_worktree(worktree, LOCK_EX);
6981 if (err)
6982 return err;
6984 if (strcmp(refname, got_worktree_get_head_ref_name(worktree)) == 0) {
6985 err = got_error_msg(GOT_ERR_SAME_BRANCH,
6986 "cannot integrate a branch into itself; "
6987 "update -b or different branch name required");
6988 goto done;
6991 err = open_fileindex(fileindex, &fileindex_path, worktree);
6992 if (err)
6993 goto done;
6995 /* Preconditions are the same as for rebase. */
6996 ok_arg.worktree = worktree;
6997 ok_arg.repo = repo;
6998 err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
6999 &ok_arg);
7000 if (err)
7001 goto done;
7003 err = got_ref_open(branch_ref, repo, refname, 1);
7004 if (err)
7005 goto done;
7007 err = got_ref_open(base_branch_ref, repo,
7008 got_worktree_get_head_ref_name(worktree), 1);
7009 done:
7010 if (err) {
7011 if (*branch_ref) {
7012 got_ref_close(*branch_ref);
7013 *branch_ref = NULL;
7015 if (*base_branch_ref) {
7016 got_ref_close(*base_branch_ref);
7017 *base_branch_ref = NULL;
7019 if (*fileindex) {
7020 got_fileindex_free(*fileindex);
7021 *fileindex = NULL;
7023 lock_worktree(worktree, LOCK_SH);
7025 return err;
7028 const struct got_error *
7029 got_worktree_integrate_continue(struct got_worktree *worktree,
7030 struct got_fileindex *fileindex, struct got_repository *repo,
7031 struct got_reference *branch_ref, struct got_reference *base_branch_ref,
7032 got_worktree_checkout_cb progress_cb, void *progress_arg,
7033 got_cancel_cb cancel_cb, void *cancel_arg)
7035 const struct got_error *err = NULL, *sync_err, *unlockerr;
7036 char *fileindex_path = NULL;
7037 struct got_object_id *tree_id = NULL, *commit_id = NULL;
7039 err = get_fileindex_path(&fileindex_path, worktree);
7040 if (err)
7041 goto done;
7043 err = got_ref_resolve(&commit_id, repo, branch_ref);
7044 if (err)
7045 goto done;
7047 err = got_object_id_by_path(&tree_id, repo, commit_id,
7048 worktree->path_prefix);
7049 if (err)
7050 goto done;
7052 err = got_worktree_set_base_commit_id(worktree, repo, commit_id);
7053 if (err)
7054 goto done;
7056 err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo,
7057 progress_cb, progress_arg, cancel_cb, cancel_arg);
7058 if (err)
7059 goto sync;
7061 err = got_ref_change_ref(base_branch_ref, commit_id);
7062 if (err)
7063 goto sync;
7065 err = got_ref_write(base_branch_ref, repo);
7066 sync:
7067 sync_err = sync_fileindex(fileindex, fileindex_path);
7068 if (sync_err && err == NULL)
7069 err = sync_err;
7071 done:
7072 unlockerr = got_ref_unlock(branch_ref);
7073 if (unlockerr && err == NULL)
7074 err = unlockerr;
7075 got_ref_close(branch_ref);
7077 unlockerr = got_ref_unlock(base_branch_ref);
7078 if (unlockerr && err == NULL)
7079 err = unlockerr;
7080 got_ref_close(base_branch_ref);
7082 got_fileindex_free(fileindex);
7083 free(fileindex_path);
7084 free(tree_id);
7086 unlockerr = lock_worktree(worktree, LOCK_SH);
7087 if (unlockerr && err == NULL)
7088 err = unlockerr;
7089 return err;
7092 const struct got_error *
7093 got_worktree_integrate_abort(struct got_worktree *worktree,
7094 struct got_fileindex *fileindex, struct got_repository *repo,
7095 struct got_reference *branch_ref, struct got_reference *base_branch_ref)
7097 const struct got_error *err = NULL, *unlockerr = NULL;
7099 got_fileindex_free(fileindex);
7101 err = lock_worktree(worktree, LOCK_SH);
7103 unlockerr = got_ref_unlock(branch_ref);
7104 if (unlockerr && err == NULL)
7105 err = unlockerr;
7106 got_ref_close(branch_ref);
7108 unlockerr = got_ref_unlock(base_branch_ref);
7109 if (unlockerr && err == NULL)
7110 err = unlockerr;
7111 got_ref_close(base_branch_ref);
7113 return err;
7116 struct check_stage_ok_arg {
7117 struct got_object_id *head_commit_id;
7118 struct got_worktree *worktree;
7119 struct got_fileindex *fileindex;
7120 struct got_repository *repo;
7121 int have_changes;
7124 const struct got_error *
7125 check_stage_ok(void *arg, unsigned char status,
7126 unsigned char staged_status, const char *relpath,
7127 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
7128 struct got_object_id *commit_id, int dirfd, const char *de_name)
7130 struct check_stage_ok_arg *a = arg;
7131 const struct got_error *err = NULL;
7132 struct got_fileindex_entry *ie;
7133 struct got_object_id base_commit_id;
7134 struct got_object_id *base_commit_idp = NULL;
7135 char *in_repo_path = NULL, *p;
7137 if (status == GOT_STATUS_UNVERSIONED ||
7138 status == GOT_STATUS_NO_CHANGE)
7139 return NULL;
7140 if (status == GOT_STATUS_NONEXISTENT)
7141 return got_error_set_errno(ENOENT, relpath);
7143 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
7144 if (ie == NULL)
7145 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
7147 if (asprintf(&in_repo_path, "%s%s%s", a->worktree->path_prefix,
7148 got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/",
7149 relpath) == -1)
7150 return got_error_from_errno("asprintf");
7152 if (got_fileindex_entry_has_commit(ie)) {
7153 memcpy(base_commit_id.sha1, ie->commit_sha1,
7154 SHA1_DIGEST_LENGTH);
7155 base_commit_idp = &base_commit_id;
7158 if (status == GOT_STATUS_CONFLICT) {
7159 err = got_error_path(ie->path, GOT_ERR_STAGE_CONFLICT);
7160 goto done;
7161 } else if (status != GOT_STATUS_ADD &&
7162 status != GOT_STATUS_MODIFY &&
7163 status != GOT_STATUS_DELETE) {
7164 err = got_error_path(ie->path, GOT_ERR_FILE_STATUS);
7165 goto done;
7168 a->have_changes = 1;
7170 p = in_repo_path;
7171 while (p[0] == '/')
7172 p++;
7173 err = check_out_of_date(p, status, staged_status,
7174 blob_id, base_commit_idp, a->head_commit_id, a->repo,
7175 GOT_ERR_STAGE_OUT_OF_DATE);
7176 done:
7177 free(in_repo_path);
7178 return err;
7181 struct stage_path_arg {
7182 struct got_worktree *worktree;
7183 struct got_fileindex *fileindex;
7184 struct got_repository *repo;
7185 got_worktree_status_cb status_cb;
7186 void *status_arg;
7187 got_worktree_patch_cb patch_cb;
7188 void *patch_arg;
7189 int staged_something;
7190 int allow_bad_symlinks;
7193 static const struct got_error *
7194 stage_path(void *arg, unsigned char status,
7195 unsigned char staged_status, const char *relpath,
7196 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
7197 struct got_object_id *commit_id, int dirfd, const char *de_name)
7199 struct stage_path_arg *a = arg;
7200 const struct got_error *err = NULL;
7201 struct got_fileindex_entry *ie;
7202 char *ondisk_path = NULL, *path_content = NULL;
7203 uint32_t stage;
7204 struct got_object_id *new_staged_blob_id = NULL;
7205 struct stat sb;
7207 if (status == GOT_STATUS_UNVERSIONED)
7208 return NULL;
7210 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
7211 if (ie == NULL)
7212 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
7214 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path,
7215 relpath)== -1)
7216 return got_error_from_errno("asprintf");
7218 switch (status) {
7219 case GOT_STATUS_ADD:
7220 case GOT_STATUS_MODIFY:
7221 /* XXX could sb.st_mode be passed in by our caller? */
7222 if (lstat(ondisk_path, &sb) == -1) {
7223 err = got_error_from_errno2("lstat", ondisk_path);
7224 break;
7226 if (a->patch_cb) {
7227 if (status == GOT_STATUS_ADD) {
7228 int choice = GOT_PATCH_CHOICE_NONE;
7229 err = (*a->patch_cb)(&choice, a->patch_arg,
7230 status, ie->path, NULL, 1, 1);
7231 if (err)
7232 break;
7233 if (choice != GOT_PATCH_CHOICE_YES)
7234 break;
7235 } else {
7236 err = create_patched_content(&path_content, 0,
7237 staged_blob_id ? staged_blob_id : blob_id,
7238 ondisk_path, dirfd, de_name, ie->path,
7239 a->repo, a->patch_cb, a->patch_arg);
7240 if (err || path_content == NULL)
7241 break;
7244 err = got_object_blob_create(&new_staged_blob_id,
7245 path_content ? path_content : ondisk_path, a->repo);
7246 if (err)
7247 break;
7248 memcpy(ie->staged_blob_sha1, new_staged_blob_id->sha1,
7249 SHA1_DIGEST_LENGTH);
7250 if (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD)
7251 stage = GOT_FILEIDX_STAGE_ADD;
7252 else
7253 stage = GOT_FILEIDX_STAGE_MODIFY;
7254 got_fileindex_entry_stage_set(ie, stage);
7255 if (S_ISLNK(sb.st_mode)) {
7256 int is_bad_symlink = 0;
7257 if (!a->allow_bad_symlinks) {
7258 char target_path[PATH_MAX];
7259 ssize_t target_len;
7260 target_len = readlink(ondisk_path, target_path,
7261 sizeof(target_path));
7262 if (target_len == -1) {
7263 err = got_error_from_errno2("readlink",
7264 ondisk_path);
7265 break;
7267 err = is_bad_symlink_target(&is_bad_symlink,
7268 target_path, target_len, ondisk_path,
7269 a->worktree->root_path);
7270 if (err)
7271 break;
7272 if (is_bad_symlink) {
7273 err = got_error_path(ondisk_path,
7274 GOT_ERR_BAD_SYMLINK);
7275 break;
7278 if (is_bad_symlink)
7279 got_fileindex_entry_staged_filetype_set(ie,
7280 GOT_FILEIDX_MODE_BAD_SYMLINK);
7281 else
7282 got_fileindex_entry_staged_filetype_set(ie,
7283 GOT_FILEIDX_MODE_SYMLINK);
7284 } else {
7285 got_fileindex_entry_staged_filetype_set(ie,
7286 GOT_FILEIDX_MODE_REGULAR_FILE);
7288 a->staged_something = 1;
7289 if (a->status_cb == NULL)
7290 break;
7291 err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE,
7292 get_staged_status(ie), relpath, blob_id,
7293 new_staged_blob_id, NULL, dirfd, de_name);
7294 break;
7295 case GOT_STATUS_DELETE:
7296 if (staged_status == GOT_STATUS_DELETE)
7297 break;
7298 if (a->patch_cb) {
7299 int choice = GOT_PATCH_CHOICE_NONE;
7300 err = (*a->patch_cb)(&choice, a->patch_arg, status,
7301 ie->path, NULL, 1, 1);
7302 if (err)
7303 break;
7304 if (choice == GOT_PATCH_CHOICE_NO)
7305 break;
7306 if (choice != GOT_PATCH_CHOICE_YES) {
7307 err = got_error(GOT_ERR_PATCH_CHOICE);
7308 break;
7311 stage = GOT_FILEIDX_STAGE_DELETE;
7312 got_fileindex_entry_stage_set(ie, stage);
7313 a->staged_something = 1;
7314 if (a->status_cb == NULL)
7315 break;
7316 err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE,
7317 get_staged_status(ie), relpath, NULL, NULL, NULL, dirfd,
7318 de_name);
7319 break;
7320 case GOT_STATUS_NO_CHANGE:
7321 break;
7322 case GOT_STATUS_CONFLICT:
7323 err = got_error_path(relpath, GOT_ERR_STAGE_CONFLICT);
7324 break;
7325 case GOT_STATUS_NONEXISTENT:
7326 err = got_error_set_errno(ENOENT, relpath);
7327 break;
7328 default:
7329 err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
7330 break;
7333 if (path_content && unlink(path_content) == -1 && err == NULL)
7334 err = got_error_from_errno2("unlink", path_content);
7335 free(path_content);
7336 free(ondisk_path);
7337 free(new_staged_blob_id);
7338 return err;
7341 const struct got_error *
7342 got_worktree_stage(struct got_worktree *worktree,
7343 struct got_pathlist_head *paths,
7344 got_worktree_status_cb status_cb, void *status_arg,
7345 got_worktree_patch_cb patch_cb, void *patch_arg,
7346 int allow_bad_symlinks, struct got_repository *repo)
7348 const struct got_error *err = NULL, *sync_err, *unlockerr;
7349 struct got_pathlist_entry *pe;
7350 struct got_fileindex *fileindex = NULL;
7351 char *fileindex_path = NULL;
7352 struct got_reference *head_ref = NULL;
7353 struct got_object_id *head_commit_id = NULL;
7354 struct check_stage_ok_arg oka;
7355 struct stage_path_arg spa;
7357 err = lock_worktree(worktree, LOCK_EX);
7358 if (err)
7359 return err;
7361 err = got_ref_open(&head_ref, repo,
7362 got_worktree_get_head_ref_name(worktree), 0);
7363 if (err)
7364 goto done;
7365 err = got_ref_resolve(&head_commit_id, repo, head_ref);
7366 if (err)
7367 goto done;
7368 err = open_fileindex(&fileindex, &fileindex_path, worktree);
7369 if (err)
7370 goto done;
7372 /* Check pre-conditions before staging anything. */
7373 oka.head_commit_id = head_commit_id;
7374 oka.worktree = worktree;
7375 oka.fileindex = fileindex;
7376 oka.repo = repo;
7377 oka.have_changes = 0;
7378 TAILQ_FOREACH(pe, paths, entry) {
7379 err = worktree_status(worktree, pe->path, fileindex, repo,
7380 check_stage_ok, &oka, NULL, NULL, 0, 0);
7381 if (err)
7382 goto done;
7384 if (!oka.have_changes) {
7385 err = got_error(GOT_ERR_STAGE_NO_CHANGE);
7386 goto done;
7389 spa.worktree = worktree;
7390 spa.fileindex = fileindex;
7391 spa.repo = repo;
7392 spa.patch_cb = patch_cb;
7393 spa.patch_arg = patch_arg;
7394 spa.status_cb = status_cb;
7395 spa.status_arg = status_arg;
7396 spa.staged_something = 0;
7397 spa.allow_bad_symlinks = allow_bad_symlinks;
7398 TAILQ_FOREACH(pe, paths, entry) {
7399 err = worktree_status(worktree, pe->path, fileindex, repo,
7400 stage_path, &spa, NULL, NULL, 0, 0);
7401 if (err)
7402 goto done;
7404 if (!spa.staged_something) {
7405 err = got_error(GOT_ERR_STAGE_NO_CHANGE);
7406 goto done;
7409 sync_err = sync_fileindex(fileindex, fileindex_path);
7410 if (sync_err && err == NULL)
7411 err = sync_err;
7412 done:
7413 if (head_ref)
7414 got_ref_close(head_ref);
7415 free(head_commit_id);
7416 free(fileindex_path);
7417 if (fileindex)
7418 got_fileindex_free(fileindex);
7419 unlockerr = lock_worktree(worktree, LOCK_SH);
7420 if (unlockerr && err == NULL)
7421 err = unlockerr;
7422 return err;
7425 struct unstage_path_arg {
7426 struct got_worktree *worktree;
7427 struct got_fileindex *fileindex;
7428 struct got_repository *repo;
7429 got_worktree_checkout_cb progress_cb;
7430 void *progress_arg;
7431 got_worktree_patch_cb patch_cb;
7432 void *patch_arg;
7435 static const struct got_error *
7436 create_unstaged_content(char **path_unstaged_content,
7437 char **path_new_staged_content, struct got_object_id *blob_id,
7438 struct got_object_id *staged_blob_id, const char *relpath,
7439 struct got_repository *repo,
7440 got_worktree_patch_cb patch_cb, void *patch_arg)
7442 const struct got_error *err, *free_err;
7443 struct got_blob_object *blob = NULL, *staged_blob = NULL;
7444 FILE *f1 = NULL, *f2 = NULL, *outfile = NULL, *rejectfile = NULL;
7445 char *path1 = NULL, *path2 = NULL, *label1 = NULL;
7446 struct got_diffreg_result *diffreg_result = NULL;
7447 int line_cur1 = 1, line_cur2 = 1, n = 0, nchunks_used = 0;
7448 int have_content = 0, have_rejected_content = 0, i = 0, nchanges = 0;
7450 *path_unstaged_content = NULL;
7451 *path_new_staged_content = NULL;
7453 err = got_object_id_str(&label1, blob_id);
7454 if (err)
7455 return err;
7456 err = got_object_open_as_blob(&blob, repo, blob_id, 8192);
7457 if (err)
7458 goto done;
7460 err = got_opentemp_named(&path1, &f1, "got-unstage-blob-base");
7461 if (err)
7462 goto done;
7464 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob);
7465 if (err)
7466 goto done;
7468 err = got_object_open_as_blob(&staged_blob, repo, staged_blob_id, 8192);
7469 if (err)
7470 goto done;
7472 err = got_opentemp_named(&path2, &f2, "got-unstage-blob-staged");
7473 if (err)
7474 goto done;
7476 err = got_object_blob_dump_to_file(NULL, NULL, NULL, f2, staged_blob);
7477 if (err)
7478 goto done;
7480 err = got_diff_files(&diffreg_result, f1, label1, f2,
7481 path2, 3, 0, 1, NULL);
7482 if (err)
7483 goto done;
7485 err = got_opentemp_named(path_unstaged_content, &outfile,
7486 "got-unstaged-content");
7487 if (err)
7488 goto done;
7489 err = got_opentemp_named(path_new_staged_content, &rejectfile,
7490 "got-new-staged-content");
7491 if (err)
7492 goto done;
7494 if (fseek(f1, 0L, SEEK_SET) == -1) {
7495 err = got_ferror(f1, GOT_ERR_IO);
7496 goto done;
7498 if (fseek(f2, 0L, SEEK_SET) == -1) {
7499 err = got_ferror(f2, GOT_ERR_IO);
7500 goto done;
7502 /* Count the number of actual changes in the diff result. */
7503 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
7504 struct diff_chunk_context cc = {};
7505 diff_chunk_context_load_change(&cc, &nchunks_used,
7506 diffreg_result->result, n, 0);
7507 nchanges++;
7509 for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) {
7510 int choice;
7511 err = apply_or_reject_change(&choice, &nchunks_used,
7512 diffreg_result->result, n, relpath, f1, f2,
7513 &line_cur1, &line_cur2,
7514 outfile, rejectfile, ++i, nchanges, patch_cb, patch_arg);
7515 if (err)
7516 goto done;
7517 if (choice == GOT_PATCH_CHOICE_YES)
7518 have_content = 1;
7519 else
7520 have_rejected_content = 1;
7521 if (choice == GOT_PATCH_CHOICE_QUIT)
7522 break;
7524 if (have_content || have_rejected_content)
7525 err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2,
7526 outfile, rejectfile);
7527 done:
7528 free(label1);
7529 if (blob)
7530 got_object_blob_close(blob);
7531 if (staged_blob)
7532 got_object_blob_close(staged_blob);
7533 free_err = got_diffreg_result_free(diffreg_result);
7534 if (free_err && err == NULL)
7535 err = free_err;
7536 if (f1 && fclose(f1) == EOF && err == NULL)
7537 err = got_error_from_errno2("fclose", path1);
7538 if (f2 && fclose(f2) == EOF && err == NULL)
7539 err = got_error_from_errno2("fclose", path2);
7540 if (outfile && fclose(outfile) == EOF && err == NULL)
7541 err = got_error_from_errno2("fclose", *path_unstaged_content);
7542 if (rejectfile && fclose(rejectfile) == EOF && err == NULL)
7543 err = got_error_from_errno2("fclose", *path_new_staged_content);
7544 if (path1 && unlink(path1) == -1 && err == NULL)
7545 err = got_error_from_errno2("unlink", path1);
7546 if (path2 && unlink(path2) == -1 && err == NULL)
7547 err = got_error_from_errno2("unlink", path2);
7548 if (err || !have_content) {
7549 if (*path_unstaged_content &&
7550 unlink(*path_unstaged_content) == -1 && err == NULL)
7551 err = got_error_from_errno2("unlink",
7552 *path_unstaged_content);
7553 free(*path_unstaged_content);
7554 *path_unstaged_content = NULL;
7556 if (err || !have_content || !have_rejected_content) {
7557 if (*path_new_staged_content &&
7558 unlink(*path_new_staged_content) == -1 && err == NULL)
7559 err = got_error_from_errno2("unlink",
7560 *path_new_staged_content);
7561 free(*path_new_staged_content);
7562 *path_new_staged_content = NULL;
7564 free(path1);
7565 free(path2);
7566 return err;
7569 static const struct got_error *
7570 unstage_hunks(struct got_object_id *staged_blob_id,
7571 struct got_blob_object *blob_base,
7572 struct got_object_id *blob_id, struct got_fileindex_entry *ie,
7573 const char *ondisk_path, const char *label_orig,
7574 struct got_worktree *worktree, struct got_repository *repo,
7575 got_worktree_patch_cb patch_cb, void *patch_arg,
7576 got_worktree_checkout_cb progress_cb, void *progress_arg)
7578 const struct got_error *err = NULL;
7579 char *path_unstaged_content = NULL;
7580 char *path_new_staged_content = NULL;
7581 struct got_object_id *new_staged_blob_id = NULL;
7582 FILE *f = NULL;
7583 struct stat sb;
7585 err = create_unstaged_content(&path_unstaged_content,
7586 &path_new_staged_content, blob_id, staged_blob_id,
7587 ie->path, repo, patch_cb, patch_arg);
7588 if (err)
7589 return err;
7591 if (path_unstaged_content == NULL)
7592 return NULL;
7594 if (path_new_staged_content) {
7595 err = got_object_blob_create(&new_staged_blob_id,
7596 path_new_staged_content, repo);
7597 if (err)
7598 goto done;
7601 f = fopen(path_unstaged_content, "r");
7602 if (f == NULL) {
7603 err = got_error_from_errno2("fopen",
7604 path_unstaged_content);
7605 goto done;
7607 if (fstat(fileno(f), &sb) == -1) {
7608 err = got_error_from_errno2("fstat", path_unstaged_content);
7609 goto done;
7611 if (got_fileindex_entry_staged_filetype_get(ie) ==
7612 GOT_FILEIDX_MODE_SYMLINK && sb.st_size < PATH_MAX) {
7613 char link_target[PATH_MAX];
7614 size_t r;
7615 r = fread(link_target, 1, sizeof(link_target), f);
7616 if (r == 0 && ferror(f)) {
7617 err = got_error_from_errno("fread");
7618 goto done;
7620 if (r >= sizeof(link_target)) { /* should not happen */
7621 err = got_error(GOT_ERR_NO_SPACE);
7622 goto done;
7624 link_target[r] = '\0';
7625 err = merge_symlink(worktree, blob_base,
7626 ondisk_path, ie->path, label_orig, link_target,
7627 worktree->base_commit_id, repo, progress_cb,
7628 progress_arg);
7629 } else {
7630 int local_changes_subsumed;
7631 err = merge_file(&local_changes_subsumed, worktree,
7632 blob_base, ondisk_path, ie->path,
7633 got_fileindex_perms_to_st(ie),
7634 path_unstaged_content, label_orig, "unstaged",
7635 repo, progress_cb, progress_arg);
7637 if (err)
7638 goto done;
7640 if (new_staged_blob_id) {
7641 memcpy(ie->staged_blob_sha1, new_staged_blob_id->sha1,
7642 SHA1_DIGEST_LENGTH);
7643 } else {
7644 got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
7645 got_fileindex_entry_staged_filetype_set(ie, 0);
7647 done:
7648 free(new_staged_blob_id);
7649 if (path_unstaged_content &&
7650 unlink(path_unstaged_content) == -1 && err == NULL)
7651 err = got_error_from_errno2("unlink", path_unstaged_content);
7652 if (path_new_staged_content &&
7653 unlink(path_new_staged_content) == -1 && err == NULL)
7654 err = got_error_from_errno2("unlink", path_new_staged_content);
7655 if (f && fclose(f) != 0 && err == NULL)
7656 err = got_error_from_errno2("fclose", path_unstaged_content);
7657 free(path_unstaged_content);
7658 free(path_new_staged_content);
7659 return err;
7662 static const struct got_error *
7663 unstage_path(void *arg, unsigned char status,
7664 unsigned char staged_status, const char *relpath,
7665 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
7666 struct got_object_id *commit_id, int dirfd, const char *de_name)
7668 const struct got_error *err = NULL;
7669 struct unstage_path_arg *a = arg;
7670 struct got_fileindex_entry *ie;
7671 struct got_blob_object *blob_base = NULL, *blob_staged = NULL;
7672 char *ondisk_path = NULL;
7673 char *id_str = NULL, *label_orig = NULL;
7674 int local_changes_subsumed;
7675 struct stat sb;
7677 if (staged_status != GOT_STATUS_ADD &&
7678 staged_status != GOT_STATUS_MODIFY &&
7679 staged_status != GOT_STATUS_DELETE)
7680 return NULL;
7682 ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
7683 if (ie == NULL)
7684 return got_error_path(relpath, GOT_ERR_FILE_STATUS);
7686 if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, relpath)
7687 == -1)
7688 return got_error_from_errno("asprintf");
7690 err = got_object_id_str(&id_str,
7691 commit_id ? commit_id : a->worktree->base_commit_id);
7692 if (err)
7693 goto done;
7694 if (asprintf(&label_orig, "%s: commit %s", GOT_MERGE_LABEL_BASE,
7695 id_str) == -1) {
7696 err = got_error_from_errno("asprintf");
7697 goto done;
7700 switch (staged_status) {
7701 case GOT_STATUS_MODIFY:
7702 err = got_object_open_as_blob(&blob_base, a->repo,
7703 blob_id, 8192);
7704 if (err)
7705 break;
7706 /* fall through */
7707 case GOT_STATUS_ADD:
7708 if (a->patch_cb) {
7709 if (staged_status == GOT_STATUS_ADD) {
7710 int choice = GOT_PATCH_CHOICE_NONE;
7711 err = (*a->patch_cb)(&choice, a->patch_arg,
7712 staged_status, ie->path, NULL, 1, 1);
7713 if (err)
7714 break;
7715 if (choice != GOT_PATCH_CHOICE_YES)
7716 break;
7717 } else {
7718 err = unstage_hunks(staged_blob_id,
7719 blob_base, blob_id, ie, ondisk_path,
7720 label_orig, a->worktree, a->repo,
7721 a->patch_cb, a->patch_arg,
7722 a->progress_cb, a->progress_arg);
7723 break; /* Done with this file. */
7726 err = got_object_open_as_blob(&blob_staged, a->repo,
7727 staged_blob_id, 8192);
7728 if (err)
7729 break;
7730 switch (got_fileindex_entry_staged_filetype_get(ie)) {
7731 case GOT_FILEIDX_MODE_BAD_SYMLINK:
7732 case GOT_FILEIDX_MODE_REGULAR_FILE:
7733 err = merge_blob(&local_changes_subsumed, a->worktree,
7734 blob_base, ondisk_path, relpath,
7735 got_fileindex_perms_to_st(ie), label_orig,
7736 blob_staged, commit_id ? commit_id :
7737 a->worktree->base_commit_id, a->repo,
7738 a->progress_cb, a->progress_arg);
7739 break;
7740 case GOT_FILEIDX_MODE_SYMLINK:
7741 if (S_ISLNK(got_fileindex_perms_to_st(ie))) {
7742 char *staged_target;
7743 err = got_object_blob_read_to_str(
7744 &staged_target, blob_staged);
7745 if (err)
7746 goto done;
7747 err = merge_symlink(a->worktree, blob_base,
7748 ondisk_path, relpath, label_orig,
7749 staged_target, commit_id ? commit_id :
7750 a->worktree->base_commit_id,
7751 a->repo, a->progress_cb, a->progress_arg);
7752 free(staged_target);
7753 } else {
7754 err = merge_blob(&local_changes_subsumed,
7755 a->worktree, blob_base, ondisk_path,
7756 relpath, got_fileindex_perms_to_st(ie),
7757 label_orig, blob_staged,
7758 commit_id ? commit_id :
7759 a->worktree->base_commit_id, a->repo,
7760 a->progress_cb, a->progress_arg);
7762 break;
7763 default:
7764 err = got_error_path(relpath, GOT_ERR_BAD_FILETYPE);
7765 break;
7767 if (err == NULL) {
7768 got_fileindex_entry_stage_set(ie,
7769 GOT_FILEIDX_STAGE_NONE);
7770 got_fileindex_entry_staged_filetype_set(ie, 0);
7772 break;
7773 case GOT_STATUS_DELETE:
7774 if (a->patch_cb) {
7775 int choice = GOT_PATCH_CHOICE_NONE;
7776 err = (*a->patch_cb)(&choice, a->patch_arg,
7777 staged_status, ie->path, NULL, 1, 1);
7778 if (err)
7779 break;
7780 if (choice == GOT_PATCH_CHOICE_NO)
7781 break;
7782 if (choice != GOT_PATCH_CHOICE_YES) {
7783 err = got_error(GOT_ERR_PATCH_CHOICE);
7784 break;
7787 got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
7788 got_fileindex_entry_staged_filetype_set(ie, 0);
7789 err = get_file_status(&status, &sb, ie, ondisk_path,
7790 dirfd, de_name, a->repo);
7791 if (err)
7792 break;
7793 err = (*a->progress_cb)(a->progress_arg, status, relpath);
7794 break;
7796 done:
7797 free(ondisk_path);
7798 if (blob_base)
7799 got_object_blob_close(blob_base);
7800 if (blob_staged)
7801 got_object_blob_close(blob_staged);
7802 free(id_str);
7803 free(label_orig);
7804 return err;
7807 const struct got_error *
7808 got_worktree_unstage(struct got_worktree *worktree,
7809 struct got_pathlist_head *paths,
7810 got_worktree_checkout_cb progress_cb, void *progress_arg,
7811 got_worktree_patch_cb patch_cb, void *patch_arg,
7812 struct got_repository *repo)
7814 const struct got_error *err = NULL, *sync_err, *unlockerr;
7815 struct got_pathlist_entry *pe;
7816 struct got_fileindex *fileindex = NULL;
7817 char *fileindex_path = NULL;
7818 struct unstage_path_arg upa;
7820 err = lock_worktree(worktree, LOCK_EX);
7821 if (err)
7822 return err;
7824 err = open_fileindex(&fileindex, &fileindex_path, worktree);
7825 if (err)
7826 goto done;
7828 upa.worktree = worktree;
7829 upa.fileindex = fileindex;
7830 upa.repo = repo;
7831 upa.progress_cb = progress_cb;
7832 upa.progress_arg = progress_arg;
7833 upa.patch_cb = patch_cb;
7834 upa.patch_arg = patch_arg;
7835 TAILQ_FOREACH(pe, paths, entry) {
7836 err = worktree_status(worktree, pe->path, fileindex, repo,
7837 unstage_path, &upa, NULL, NULL, 0, 0);
7838 if (err)
7839 goto done;
7842 sync_err = sync_fileindex(fileindex, fileindex_path);
7843 if (sync_err && err == NULL)
7844 err = sync_err;
7845 done:
7846 free(fileindex_path);
7847 if (fileindex)
7848 got_fileindex_free(fileindex);
7849 unlockerr = lock_worktree(worktree, LOCK_SH);
7850 if (unlockerr && err == NULL)
7851 err = unlockerr;
7852 return err;
7855 struct report_file_info_arg {
7856 struct got_worktree *worktree;
7857 got_worktree_path_info_cb info_cb;
7858 void *info_arg;
7859 struct got_pathlist_head *paths;
7860 got_cancel_cb cancel_cb;
7861 void *cancel_arg;
7864 static const struct got_error *
7865 report_file_info(void *arg, struct got_fileindex_entry *ie)
7867 struct report_file_info_arg *a = arg;
7868 struct got_pathlist_entry *pe;
7869 struct got_object_id blob_id, staged_blob_id, commit_id;
7870 struct got_object_id *blob_idp = NULL, *staged_blob_idp = NULL;
7871 struct got_object_id *commit_idp = NULL;
7872 int stage;
7874 if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
7875 return got_error(GOT_ERR_CANCELLED);
7877 TAILQ_FOREACH(pe, a->paths, entry) {
7878 if (pe->path_len == 0 || strcmp(pe->path, ie->path) == 0 ||
7879 got_path_is_child(ie->path, pe->path, pe->path_len))
7880 break;
7882 if (pe == NULL) /* not found */
7883 return NULL;
7885 if (got_fileindex_entry_has_blob(ie)) {
7886 memcpy(blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
7887 blob_idp = &blob_id;
7889 stage = got_fileindex_entry_stage_get(ie);
7890 if (stage == GOT_FILEIDX_STAGE_MODIFY ||
7891 stage == GOT_FILEIDX_STAGE_ADD) {
7892 memcpy(staged_blob_id.sha1, ie->staged_blob_sha1,
7893 SHA1_DIGEST_LENGTH);
7894 staged_blob_idp = &staged_blob_id;
7897 if (got_fileindex_entry_has_commit(ie)) {
7898 memcpy(commit_id.sha1, ie->commit_sha1, SHA1_DIGEST_LENGTH);
7899 commit_idp = &commit_id;
7902 return a->info_cb(a->info_arg, ie->path, got_fileindex_perms_to_st(ie),
7903 (time_t)ie->mtime_sec, blob_idp, staged_blob_idp, commit_idp);
7906 const struct got_error *
7907 got_worktree_path_info(struct got_worktree *worktree,
7908 struct got_pathlist_head *paths,
7909 got_worktree_path_info_cb info_cb, void *info_arg,
7910 got_cancel_cb cancel_cb, void *cancel_arg)
7913 const struct got_error *err = NULL, *unlockerr;
7914 struct got_fileindex *fileindex = NULL;
7915 char *fileindex_path = NULL;
7916 struct report_file_info_arg arg;
7918 err = lock_worktree(worktree, LOCK_SH);
7919 if (err)
7920 return err;
7922 err = open_fileindex(&fileindex, &fileindex_path, worktree);
7923 if (err)
7924 goto done;
7926 arg.worktree = worktree;
7927 arg.info_cb = info_cb;
7928 arg.info_arg = info_arg;
7929 arg.paths = paths;
7930 arg.cancel_cb = cancel_cb;
7931 arg.cancel_arg = cancel_arg;
7932 err = got_fileindex_for_each_entry_safe(fileindex, report_file_info,
7933 &arg);
7934 done:
7935 free(fileindex_path);
7936 if (fileindex)
7937 got_fileindex_free(fileindex);
7938 unlockerr = lock_worktree(worktree, LOCK_UN);
7939 if (unlockerr && err == NULL)
7940 err = unlockerr;
7941 return err;