2 * Copyright (c) 2022 Omar Polo <op@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * Things that we may want to support:
19 * + support indented patches?
20 * + support other kinds of patches?
22 #include "got_compat.h"
24 #include <sys/types.h>
25 #include <sys/queue.h>
26 #include <sys/socket.h>
39 #include "got_error.h"
40 #include "got_object.h"
42 #include "got_reference.h"
43 #include "got_cancel.h"
44 #include "got_worktree.h"
45 #include "got_repository.h"
46 #include "got_opentemp.h"
47 #include "got_patch.h"
50 #include "got_lib_delta.h"
51 #include "got_lib_diff.h"
52 #include "got_lib_object.h"
53 #include "got_lib_privsep.h"
54 #include "got_lib_hash.h"
57 #define MIN(a, b) ((a) < (b) ? (a) : (b))
60 struct got_patch_hunk
{
61 STAILQ_ENTRY(got_patch_hunk
) entries
;
62 const struct got_error
*err
;
76 STAILQ_HEAD(got_patch_hunk_head
, got_patch_hunk
);
83 struct got_patch_hunk_head head
;
87 got_patch_progress_cb progress_cb
;
89 struct got_patch_hunk_head
*head
;
93 apply_umask(mode_t mode
)
102 static const struct got_error
*
103 send_patch(struct imsgbuf
*ibuf
, int fd
)
105 const struct got_error
*err
= NULL
;
107 if (imsg_compose(ibuf
, GOT_IMSG_PATCH_FILE
, 0, 0, fd
,
109 err
= got_error_from_errno(
110 "imsg_compose GOT_IMSG_PATCH_FILE");
115 return got_privsep_flush_imsg(ibuf
);
119 patch_free(struct got_patch
*p
)
121 struct got_patch_hunk
*h
;
124 while (!STAILQ_EMPTY(&p
->head
)) {
125 h
= STAILQ_FIRST(&p
->head
);
126 STAILQ_REMOVE_HEAD(&p
->head
, entries
);
128 for (i
= 0; i
< h
->len
; ++i
)
137 memset(p
, 0, sizeof(*p
));
138 STAILQ_INIT(&p
->head
);
141 static const struct got_error
*
142 pushline(struct got_patch_hunk
*h
, const char *line
)
147 if (h
->len
== h
->cap
) {
148 if ((newcap
= h
->cap
* 1.5) == 0)
150 t
= recallocarray(h
->lines
, h
->cap
, newcap
,
151 sizeof(h
->lines
[0]));
153 return got_error_from_errno("recallocarray");
158 if ((t
= strdup(line
)) == NULL
)
159 return got_error_from_errno("strdup");
161 h
->lines
[h
->len
++] = t
;
165 static const struct got_error
*
166 recv_patch(struct imsgbuf
*ibuf
, int *done
, struct got_patch
*p
, int strip
)
168 const struct got_error
*err
= NULL
;
170 struct got_imsg_patch_hunk hdr
;
171 struct got_imsg_patch patch
;
172 struct got_patch_hunk
*h
= NULL
;
176 memset(p
, 0, sizeof(*p
));
177 STAILQ_INIT(&p
->head
);
179 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
182 if (imsg
.hdr
.type
== GOT_IMSG_PATCH_EOF
) {
186 if (imsg
.hdr
.type
!= GOT_IMSG_PATCH
) {
187 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
190 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
191 if (datalen
!= sizeof(patch
)) {
192 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
195 memcpy(&patch
, imsg
.data
, sizeof(patch
));
197 if (patch
.old
[sizeof(patch
.old
)-1] != '\0' ||
198 patch
.new[sizeof(patch
.new)-1] != '\0' ||
199 patch
.cid
[sizeof(patch
.cid
)-1] != '\0' ||
200 patch
.blob
[sizeof(patch
.blob
)-1] != '\0') {
201 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
205 if (*patch
.cid
!= '\0')
206 strlcpy(p
->cid
, patch
.cid
, sizeof(p
->cid
));
208 if (*patch
.blob
!= '\0')
209 strlcpy(p
->blob
, patch
.blob
, sizeof(p
->blob
));
211 p
->xbit
= patch
.xbit
;
213 /* automatically set strip=1 for git-style diffs */
214 if (strip
== -1 && patch
.git
&&
215 (*patch
.old
== '\0' || !strncmp(patch
.old
, "a/", 2)) &&
216 (*patch
.new == '\0' || !strncmp(patch
.new, "b/", 2)))
219 /* prefer the new name if not /dev/null for not git-style diffs */
220 if (!patch
.git
&& *patch
.new != '\0' && *patch
.old
!= '\0') {
221 err
= got_path_strip(&p
->old
, patch
.new, strip
);
224 } else if (*patch
.old
!= '\0') {
225 err
= got_path_strip(&p
->old
, patch
.old
, strip
);
230 if (*patch
.new != '\0') {
231 err
= got_path_strip(&p
->new, patch
.new, strip
);
236 if (p
->old
== NULL
&& p
->new == NULL
) {
237 err
= got_error(GOT_ERR_PATCH_MALFORMED
);
246 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
252 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
253 switch (imsg
.hdr
.type
) {
254 case GOT_IMSG_PATCH_DONE
:
255 if (h
!= NULL
&& h
->len
== 0)
256 err
= got_error(GOT_ERR_PATCH_MALFORMED
);
258 case GOT_IMSG_PATCH_HUNK
:
260 (h
->len
== 0 || h
->old_nonl
|| h
->new_nonl
)) {
261 err
= got_error(GOT_ERR_PATCH_MALFORMED
);
265 if (datalen
!= sizeof(hdr
)) {
266 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
269 memcpy(&hdr
, imsg
.data
, sizeof(hdr
));
270 if (hdr
.oldfrom
< 0 || hdr
.newfrom
< 0) {
271 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
274 if ((h
= calloc(1, sizeof(*h
))) == NULL
) {
275 err
= got_error_from_errno("calloc");
278 h
->old_from
= hdr
.oldfrom
;
279 h
->old_lines
= hdr
.oldlines
;
280 h
->new_from
= hdr
.newfrom
;
281 h
->new_lines
= hdr
.newlines
;
282 STAILQ_INSERT_TAIL(&p
->head
, h
, entries
);
284 case GOT_IMSG_PATCH_LINE
:
286 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
290 /* at least one char */
291 if (datalen
< 2 || t
[datalen
-1] != '\0') {
292 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
295 if (*t
!= ' ' && *t
!= '-' && *t
!= '+' &&
297 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
302 err
= pushline(h
, t
);
303 else if (lastmode
== '-')
305 else if (lastmode
== '+')
308 err
= got_error(GOT_ERR_PATCH_MALFORMED
);
316 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
332 reverse_patch(struct got_patch
*p
)
334 struct got_patch_hunk
*h
;
338 STAILQ_FOREACH(h
, &p
->head
, entries
) {
340 h
->old_from
= h
->new_from
;
344 h
->old_lines
= h
->new_lines
;
348 h
->old_nonl
= h
->new_nonl
;
351 for (i
= 0; i
< h
->len
; ++i
) {
352 if (*h
->lines
[i
] == '+')
354 else if (*h
->lines
[i
] == '-')
361 * Copy data from orig starting at copypos until pos into tmp.
362 * If pos is -1, copy until EOF.
364 static const struct got_error
*
365 copy(FILE *tmp
, FILE *orig
, off_t copypos
, off_t pos
)
370 if (fseeko(orig
, copypos
, SEEK_SET
) == -1)
371 return got_error_from_errno("fseeko");
373 while (pos
== -1 || copypos
< pos
) {
376 len
= MIN(len
, (size_t)pos
- copypos
);
377 r
= fread(buf
, 1, len
, orig
);
378 if (r
!= len
&& ferror(orig
))
379 return got_error_from_errno("fread");
380 w
= fwrite(buf
, 1, r
, tmp
);
382 return got_error_from_errno("fwrite");
384 if (r
!= len
&& feof(orig
)) {
387 return got_error(GOT_ERR_HUNK_FAILED
);
393 static int linecmp(const char *, const char *, int *);
395 static const struct got_error
*
396 locate_hunk(FILE *orig
, struct got_patch_hunk
*h
, off_t
*pos
, int *lineno
)
398 const struct got_error
*err
= NULL
;
400 char mode
= *h
->lines
[0];
404 int mangled
= 0, match_lineno
= -1;
407 linelen
= getline(&line
, &linesize
, orig
);
410 err
= got_error_from_errno("getline");
411 else if (match
== -1)
412 err
= got_error(GOT_ERR_HUNK_FAILED
);
415 if (line
[linelen
- 1] == '\n')
416 line
[linelen
- 1] = '\0';
419 if ((mode
== ' ' && !linecmp(h
->lines
[0] + 1, line
, &mangled
)) ||
420 (mode
== '-' && !linecmp(h
->lines
[0] + 1, line
, &mangled
)) ||
421 (mode
== '+' && *lineno
== h
->old_from
)) {
422 match
= ftello(orig
);
424 err
= got_error_from_errno("ftello");
428 match_lineno
= (*lineno
)-1;
431 if (*lineno
>= h
->old_from
&& match
!= -1) {
440 *lineno
= match_lineno
;
441 if (fseeko(orig
, match
, SEEK_SET
) == -1)
442 err
= got_error_from_errno("fseeko");
450 linecmp(const char *a
, const char *b
, int *mangled
)
461 while (*a
== '\t' || *a
== ' ' || *a
== '\f')
463 while (*b
== '\t' || *b
== ' ' || *b
== '\f')
465 if (*a
== '\0' || *a
!= *b
)
473 static const struct got_error
*
474 test_hunk(FILE *orig
, struct got_patch_hunk
*h
)
476 const struct got_error
*err
= NULL
;
478 size_t linesize
= 0, i
= 0;
482 for (i
= 0; i
< h
->len
; ++i
) {
483 switch (*h
->lines
[i
]) {
488 linelen
= getline(&line
, &linesize
, orig
);
491 err
= got_error_from_errno("getline");
494 GOT_ERR_HUNK_FAILED
);
497 if (line
[linelen
- 1] == '\n')
498 line
[linelen
- 1] = '\0';
499 if (linecmp(h
->lines
[i
] + 1, line
, &mangled
)) {
500 err
= got_error(GOT_ERR_HUNK_FAILED
);
514 static const struct got_error
*
515 apply_hunk(FILE *orig
, FILE *tmp
, struct got_patch_hunk
*h
, int *lineno
,
518 const struct got_error
*err
= NULL
;
520 size_t linesize
= 0, i
, new = 0;
525 if (orig
!= NULL
&& fseeko(orig
, from
, SEEK_SET
) == -1)
526 return got_error_from_errno("fseeko");
528 for (i
= 0; i
< h
->len
; ++i
) {
529 switch (mode
= *h
->lines
[i
]) {
534 linelen
= getline(&line
, &linesize
, orig
);
536 err
= got_error_from_errno("getline");
539 if (line
[linelen
- 1] == '\n')
540 line
[linelen
- 1] = '\0';
546 if (fprintf(tmp
, "%s\n", t
) < 0) {
547 err
= got_error_from_errno("fprintf");
553 if (fprintf(tmp
, "%s", h
->lines
[i
] + 1) < 0) {
554 err
= got_error_from_errno("fprintf");
557 if (new != h
->new_lines
|| !h
->new_nonl
) {
558 if (fprintf(tmp
, "\n") < 0) {
559 err
= got_error_from_errno("fprintf");
572 static const struct got_error
*
573 patch_file(struct got_patch
*p
, FILE *orig
, FILE *tmp
)
575 const struct got_error
*err
= NULL
;
576 struct got_patch_hunk
*h
;
584 if (p
->old
== NULL
) { /* create */
585 h
= STAILQ_FIRST(&p
->head
);
586 if (h
== NULL
|| STAILQ_NEXT(h
, entries
) != NULL
)
587 return got_error(GOT_ERR_PATCH_MALFORMED
);
588 return apply_hunk(orig
, tmp
, h
, &lineno
, 0);
591 /* When deleting binary files there are no hunks to apply. */
592 if (p
->new == NULL
&& STAILQ_EMPTY(&p
->head
))
595 if (fstat(fileno(orig
), &sb
) == -1)
596 return got_error_from_errno("fstat");
599 STAILQ_FOREACH(h
, &p
->head
, entries
) {
601 err
= locate_hunk(orig
, h
, &pos
, &lineno
);
602 if (err
!= NULL
&& err
->code
== GOT_ERR_HUNK_FAILED
)
606 err
= copy(tmp
, orig
, copypos
, pos
);
611 err
= test_hunk(orig
, h
);
612 if (err
!= NULL
&& err
->code
== GOT_ERR_HUNK_FAILED
) {
614 * try to apply the hunk again starting the search
615 * after the previous partial match.
617 if (fseeko(orig
, pos
, SEEK_SET
) == -1)
618 return got_error_from_errno("fseeko");
619 linelen
= getline(&line
, &linesize
, orig
);
621 return got_error_from_errno("getline");
628 if (lineno
+ 1 != h
->old_from
)
629 h
->offset
= lineno
+ 1 - h
->old_from
;
631 err
= apply_hunk(orig
, tmp
, h
, &lineno
, pos
);
635 copypos
= ftello(orig
);
637 return got_error_from_errno("ftello");
640 if (p
->new == NULL
&& sb
.st_size
!= copypos
) {
641 h
= STAILQ_FIRST(&p
->head
);
642 h
->err
= got_error(GOT_ERR_HUNK_FAILED
);
644 } else if (!feof(orig
))
645 err
= copy(tmp
, orig
, copypos
, -1);
650 static const struct got_error
*
651 report_progress(struct patch_args
*pa
, const char *old
, const char *new,
652 unsigned char status
, const struct got_error
*orig_error
)
654 const struct got_error
*err
;
655 struct got_patch_hunk
*h
;
657 err
= pa
->progress_cb(pa
->progress_arg
, old
, new, status
,
658 orig_error
, 0, 0, 0, 0, 0, 0, NULL
);
662 STAILQ_FOREACH(h
, pa
->head
, entries
) {
663 if (h
->offset
== 0 && !h
->ws_mangled
&& h
->err
== NULL
)
666 err
= pa
->progress_cb(pa
->progress_arg
, old
, new, 0, NULL
,
667 h
->old_from
, h
->old_lines
, h
->new_from
, h
->new_lines
,
668 h
->offset
, h
->ws_mangled
, h
->err
);
676 static const struct got_error
*
677 patch_delete(void *arg
, unsigned char status
, unsigned char staged_status
,
680 return report_progress(arg
, path
, NULL
, status
, NULL
);
683 static const struct got_error
*
684 patch_add(void *arg
, unsigned char status
, const char *path
)
686 return report_progress(arg
, NULL
, path
, status
, NULL
);
689 static const struct got_error
*
690 open_blob(char **path
, FILE **fp
, const char *blobid
,
691 struct got_repository
*repo
)
693 const struct got_error
*err
= NULL
;
694 struct got_blob_object
*blob
= NULL
;
695 struct got_object_id id
, *idptr
, *matched_id
= NULL
;
701 if (strlen(blobid
) != SHA1_DIGEST_STRING_LENGTH
- 1) {
702 err
= got_repo_match_object_id(&matched_id
, NULL
, blobid
,
703 GOT_OBJ_TYPE_BLOB
, NULL
/* do not resolve tags */,
709 if (!got_parse_object_id(&id
, blobid
, GOT_HASH_SHA1
))
710 return got_error(GOT_ERR_BAD_OBJ_ID_STR
);
714 fd
= got_opentempfd();
716 err
= got_error_from_errno("got_opentempfd");
720 err
= got_object_open_as_blob(&blob
, repo
, idptr
, 8192, fd
);
724 err
= got_opentemp_named(path
, fp
, GOT_TMPDIR_STR
"/got-patch-blob",
729 err
= got_object_blob_dump_to_file(NULL
, NULL
, NULL
, *fp
, blob
);
734 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
735 err
= got_error_from_errno("close");
737 got_object_blob_close(blob
);
738 if (matched_id
!= NULL
)
752 static const struct got_error
*
753 prepare_merge(int *do_merge
, char **apath
, FILE **afile
,
754 struct got_worktree
*worktree
, struct got_repository
*repo
,
755 struct got_patch
*p
, struct got_object_id
*commit_id
,
756 struct got_tree_object
*tree
, const char *path
)
758 const struct got_error
*err
= NULL
;
764 /* don't run the diff3 merge on creations/deletions */
765 if (p
->old
== NULL
|| p
->new == NULL
)
769 struct got_object_id
*id
;
771 err
= got_object_tree_find_path(&id
, NULL
, repo
, tree
, path
);
774 got_sha1_digest_to_str(id
->sha1
, p
->blob
, sizeof(p
->blob
));
775 got_sha1_digest_to_str(commit_id
->sha1
, p
->cid
, sizeof(p
->cid
));
777 err
= open_blob(apath
, afile
, p
->blob
, repo
);
778 *do_merge
= err
== NULL
;
779 } else if (*p
->blob
!= '\0') {
780 err
= open_blob(apath
, afile
, p
->blob
, repo
);
782 * ignore failures to open this blob, we might have
785 if (err
&& !(err
->code
== GOT_ERR_ERRNO
&& errno
== ENOENT
) &&
786 err
->code
!= GOT_ERR_NO_OBJ
)
788 *do_merge
= err
== NULL
;
795 static const struct got_error
*
796 apply_patch(int *overlapcnt
, struct got_worktree
*worktree
,
797 struct got_repository
*repo
, struct got_fileindex
*fileindex
,
798 const char *old
, const char *new, struct got_patch
*p
, int nop
,
799 int reverse
, struct got_object_id
*commit_id
,
800 struct got_tree_object
*tree
, struct patch_args
*pa
,
801 got_cancel_cb cancel_cb
, void *cancel_arg
)
803 const struct got_error
*err
= NULL
;
805 int do_merge
= 0, file_renamed
= 0;
806 char *oldlabel
= NULL
, *newlabel
= NULL
, *anclabel
= NULL
;
807 char *oldpath
= NULL
, *newpath
= NULL
;
808 char *tmppath
= NULL
, *template = NULL
;
809 char *apath
= NULL
, *mergepath
= NULL
;
810 FILE *oldfile
= NULL
, *tmpfile
= NULL
, *afile
= NULL
, *mergefile
= NULL
;
812 mode_t mode
= GOT_DEFAULT_FILE_MODE
;
816 err
= prepare_merge(&do_merge
, &apath
, &afile
, worktree
, repo
, p
,
817 commit_id
, tree
, old
);
821 if (reverse
&& !do_merge
)
824 if (asprintf(&oldpath
, "%s/%s", got_worktree_get_root_path(worktree
),
826 err
= got_error_from_errno("asprintf");
830 if (asprintf(&newpath
, "%s/%s", got_worktree_get_root_path(worktree
),
832 err
= got_error_from_errno("asprintf");
836 file_renamed
= strcmp(oldpath
, newpath
);
838 if (asprintf(&template, "%s/got-patch",
839 got_worktree_get_root_path(worktree
)) == -1) {
840 err
= got_error_from_errno(template);
844 if (p
->old
!= NULL
) {
845 if ((oldfile
= fopen(oldpath
, "r")) == NULL
) {
846 err
= got_error_from_errno2("open", oldpath
);
849 if (fstat(fileno(oldfile
), &sb
) == -1) {
850 err
= got_error_from_errno2("fstat", oldpath
);
855 mode
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
857 err
= got_opentemp_named(&tmppath
, &tmpfile
, template, "");
860 outfd
= fileno(tmpfile
);
861 err
= patch_file(p
, afile
!= NULL
? afile
: oldfile
, tmpfile
);
866 const char *type
, *id
;
868 if (fseeko(afile
, 0, SEEK_SET
) == -1 ||
869 fseeko(oldfile
, 0, SEEK_SET
) == -1 ||
870 fseeko(tmpfile
, 0, SEEK_SET
) == -1) {
871 err
= got_error_from_errno("fseeko");
875 if (asprintf(&oldlabel
, "--- %s", p
->old
) == -1) {
876 err
= got_error_from_errno("asprintf");
881 if (asprintf(&newlabel
, "+++ %s", p
->new) == -1) {
882 err
= got_error_from_errno("asprintf");
887 if (*p
->cid
!= '\0') {
895 if (asprintf(&anclabel
, "%s %s", type
, id
) == -1) {
896 err
= got_error_from_errno("asprintf");
914 err
= got_opentemp_named(&mergepath
, &mergefile
, template, "");
917 outfd
= fileno(mergefile
);
919 err
= got_merge_diff3(overlapcnt
, outfd
, tmpfile
, afile
,
920 oldfile
, oldlabel
, anclabel
, newlabel
,
921 GOT_DIFF_ALGORITHM_PATIENCE
);
929 if (p
->old
!= NULL
&& p
->new == NULL
) {
930 err
= got_worktree_patch_schedule_rm(old
, repo
, worktree
,
931 fileindex
, patch_delete
, pa
);
935 if (fchmod(outfd
, apply_umask(mode
)) == -1) {
936 err
= got_error_from_errno2("chmod", tmppath
);
941 err
= got_path_move_file(mergepath
, newpath
);
947 err
= got_path_move_file(tmppath
, newpath
);
955 err
= got_worktree_patch_schedule_rm(old
, repo
, worktree
,
956 fileindex
, patch_delete
, pa
);
958 err
= got_worktree_patch_schedule_add(new, repo
,
959 worktree
, fileindex
, patch_add
,
963 } else if (p
->old
== NULL
) {
964 err
= got_worktree_patch_schedule_add(new, repo
, worktree
,
965 fileindex
, patch_add
, pa
);
968 } else if (*overlapcnt
!= 0)
969 err
= report_progress(pa
, old
, new, GOT_STATUS_CONFLICT
, NULL
);
971 err
= report_progress(pa
, old
, new, GOT_STATUS_MERGE
, NULL
);
973 err
= report_progress(pa
, old
, new, GOT_STATUS_MODIFY
, NULL
);
978 if (tmppath
!= NULL
&& unlink(tmppath
) == -1 && err
== NULL
)
979 err
= got_error_from_errno("unlink");
980 if (tmpfile
!= NULL
&& fclose(tmpfile
) == EOF
&& err
== NULL
)
981 err
= got_error_from_errno("fclose");
985 if (oldfile
!= NULL
&& fclose(oldfile
) == EOF
&& err
== NULL
)
986 err
= got_error_from_errno("fclose");
988 if (apath
!= NULL
&& unlink(apath
) == -1 && err
== NULL
)
989 err
= got_error_from_errno("unlink");
990 if (afile
!= NULL
&& fclose(afile
) == EOF
&& err
== NULL
)
991 err
= got_error_from_errno("fclose");
994 if (mergepath
!= NULL
&& unlink(mergepath
) == -1 && err
== NULL
)
995 err
= got_error_from_errno("unlink");
996 if (mergefile
!= NULL
&& fclose(mergefile
) == EOF
&& err
== NULL
)
997 err
= got_error_from_errno("fclose");
1007 const struct got_error
*
1008 got_patch(int fd
, struct got_worktree
*worktree
, struct got_repository
*repo
,
1009 int nop
, int strip
, int reverse
, struct got_object_id
*commit_id
,
1010 got_patch_progress_cb progress_cb
, void *progress_arg
,
1011 got_cancel_cb cancel_cb
, void *cancel_arg
)
1013 const struct got_error
*err
= NULL
, *complete_err
= NULL
;
1014 struct got_fileindex
*fileindex
= NULL
;
1015 struct got_commit_object
*commit
= NULL
;
1016 struct got_tree_object
*tree
= NULL
;
1017 char *fileindex_path
= NULL
;
1018 char *oldpath
, *newpath
;
1019 struct imsgbuf
*ibuf
;
1020 int imsg_fds
[2] = {-1, -1};
1021 int overlapcnt
, done
= 0, failed
= 0;
1024 ibuf
= calloc(1, sizeof(*ibuf
));
1026 err
= got_error_from_errno("calloc");
1030 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
1031 err
= got_error_from_errno("socketpair");
1037 err
= got_error_from_errno("fork");
1039 } else if (pid
== 0) {
1040 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_PATCH
,
1045 if (close(imsg_fds
[1]) == -1) {
1046 err
= got_error_from_errno("close");
1050 imsg_init(ibuf
, imsg_fds
[0]);
1052 err
= send_patch(ibuf
, fd
);
1057 err
= got_worktree_patch_prepare(&fileindex
, &fileindex_path
,
1063 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
1067 err
= got_object_open_as_tree(&tree
, repo
, commit
->tree_id
);
1072 while (!done
&& err
== NULL
) {
1074 struct patch_args pa
;
1076 pa
.progress_cb
= progress_cb
;
1077 pa
.progress_arg
= progress_arg
;
1080 err
= recv_patch(ibuf
, &done
, &p
, strip
);
1084 err
= got_worktree_patch_check_path(p
.old
, p
.new, &oldpath
,
1085 &newpath
, worktree
, repo
, fileindex
);
1087 err
= apply_patch(&overlapcnt
, worktree
, repo
,
1088 fileindex
, oldpath
, newpath
, &p
, nop
, reverse
,
1089 commit_id
, tree
, &pa
, cancel_cb
, cancel_arg
);
1092 /* recoverable errors */
1093 if (err
->code
== GOT_ERR_FILE_STATUS
||
1094 (err
->code
== GOT_ERR_ERRNO
&& errno
== ENOENT
))
1095 err
= report_progress(&pa
, p
.old
, p
.new,
1096 GOT_STATUS_CANNOT_UPDATE
, err
);
1097 else if (err
->code
== GOT_ERR_HUNK_FAILED
)
1098 err
= report_progress(&pa
, p
.old
, p
.new,
1099 GOT_STATUS_CANNOT_UPDATE
, NULL
);
1101 if (overlapcnt
!= 0)
1113 if (fileindex
!= NULL
)
1114 complete_err
= got_worktree_patch_complete(fileindex
,
1116 if (complete_err
&& err
== NULL
)
1118 free(fileindex_path
);
1120 got_object_tree_close(tree
);
1122 got_object_commit_close(commit
);
1123 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
1124 err
= got_error_from_errno("close");
1127 if (imsg_fds
[0] != -1 && close(imsg_fds
[0]) == -1 && err
== NULL
)
1128 err
= got_error_from_errno("close");
1129 if (imsg_fds
[1] != -1 && close(imsg_fds
[1]) == -1 && err
== NULL
)
1130 err
= got_error_from_errno("close");
1131 if (err
== NULL
&& failed
)
1132 err
= got_error(GOT_ERR_PATCH_FAILED
);