Bug Summary

File:got/got.c
Warning:line 507, column 10
Although the value stored to 'linelen' is used in the enclosing expression, the value is never actually read from 'linelen'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd6.9 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name got.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/11.1.0 -I /home/ben/Projects/got/got/../include -I /home/ben/Projects/got/got/../lib -D GOT_LIBEXECDIR=/home/ben/bin -D GOT_VERSION=0.53-current -internal-isystem /usr/local/lib/clang/11.1.0/include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir /home/ben/Projects/got/got/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/got/scan/2021-05-28-230913-68537-1 -x c /home/ben/Projects/got/got/got.c
1/*
2 * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/queue.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/param.h>
23#include <sys/wait.h>
24
25#include <err.h>
26#include <errno(*__errno()).h>
27#include <fcntl.h>
28#include <limits.h>
29#include <locale.h>
30#include <ctype.h>
31#include <signal.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include <libgen.h>
37#include <time.h>
38#include <paths.h>
39#include <regex.h>
40#include <getopt.h>
41#include <util.h>
42
43#include "got_version.h"
44#include "got_error.h"
45#include "got_object.h"
46#include "got_reference.h"
47#include "got_repository.h"
48#include "got_path.h"
49#include "got_cancel.h"
50#include "got_worktree.h"
51#include "got_diff.h"
52#include "got_commit_graph.h"
53#include "got_fetch.h"
54#include "got_blame.h"
55#include "got_privsep.h"
56#include "got_opentemp.h"
57#include "got_gotconfig.h"
58
59#ifndef nitems
60#define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0]))
61#endif
62
63static volatile sig_atomic_t sigint_received;
64static volatile sig_atomic_t sigpipe_received;
65
66static void
67catch_sigint(int signo)
68{
69 sigint_received = 1;
70}
71
72static void
73catch_sigpipe(int signo)
74{
75 sigpipe_received = 1;
76}
77
78
79struct got_cmd {
80 const char *cmd_name;
81 const struct got_error *(*cmd_main)(int, char *[]);
82 void (*cmd_usage)(void);
83 const char *cmd_alias;
84};
85
86__dead__attribute__((__noreturn__)) static void usage(int, int);
87__dead__attribute__((__noreturn__)) static void usage_init(void);
88__dead__attribute__((__noreturn__)) static void usage_import(void);
89__dead__attribute__((__noreturn__)) static void usage_clone(void);
90__dead__attribute__((__noreturn__)) static void usage_fetch(void);
91__dead__attribute__((__noreturn__)) static void usage_checkout(void);
92__dead__attribute__((__noreturn__)) static void usage_update(void);
93__dead__attribute__((__noreturn__)) static void usage_log(void);
94__dead__attribute__((__noreturn__)) static void usage_diff(void);
95__dead__attribute__((__noreturn__)) static void usage_blame(void);
96__dead__attribute__((__noreturn__)) static void usage_tree(void);
97__dead__attribute__((__noreturn__)) static void usage_status(void);
98__dead__attribute__((__noreturn__)) static void usage_ref(void);
99__dead__attribute__((__noreturn__)) static void usage_branch(void);
100__dead__attribute__((__noreturn__)) static void usage_tag(void);
101__dead__attribute__((__noreturn__)) static void usage_add(void);
102__dead__attribute__((__noreturn__)) static void usage_remove(void);
103__dead__attribute__((__noreturn__)) static void usage_revert(void);
104__dead__attribute__((__noreturn__)) static void usage_commit(void);
105__dead__attribute__((__noreturn__)) static void usage_cherrypick(void);
106__dead__attribute__((__noreturn__)) static void usage_backout(void);
107__dead__attribute__((__noreturn__)) static void usage_rebase(void);
108__dead__attribute__((__noreturn__)) static void usage_histedit(void);
109__dead__attribute__((__noreturn__)) static void usage_integrate(void);
110__dead__attribute__((__noreturn__)) static void usage_stage(void);
111__dead__attribute__((__noreturn__)) static void usage_unstage(void);
112__dead__attribute__((__noreturn__)) static void usage_cat(void);
113__dead__attribute__((__noreturn__)) static void usage_info(void);
114
115static const struct got_error* cmd_init(int, char *[]);
116static const struct got_error* cmd_import(int, char *[]);
117static const struct got_error* cmd_clone(int, char *[]);
118static const struct got_error* cmd_fetch(int, char *[]);
119static const struct got_error* cmd_checkout(int, char *[]);
120static const struct got_error* cmd_update(int, char *[]);
121static const struct got_error* cmd_log(int, char *[]);
122static const struct got_error* cmd_diff(int, char *[]);
123static const struct got_error* cmd_blame(int, char *[]);
124static const struct got_error* cmd_tree(int, char *[]);
125static const struct got_error* cmd_status(int, char *[]);
126static const struct got_error* cmd_ref(int, char *[]);
127static const struct got_error* cmd_branch(int, char *[]);
128static const struct got_error* cmd_tag(int, char *[]);
129static const struct got_error* cmd_add(int, char *[]);
130static const struct got_error* cmd_remove(int, char *[]);
131static const struct got_error* cmd_revert(int, char *[]);
132static const struct got_error* cmd_commit(int, char *[]);
133static const struct got_error* cmd_cherrypick(int, char *[]);
134static const struct got_error* cmd_backout(int, char *[]);
135static const struct got_error* cmd_rebase(int, char *[]);
136static const struct got_error* cmd_histedit(int, char *[]);
137static const struct got_error* cmd_integrate(int, char *[]);
138static const struct got_error* cmd_stage(int, char *[]);
139static const struct got_error* cmd_unstage(int, char *[]);
140static const struct got_error* cmd_cat(int, char *[]);
141static const struct got_error* cmd_info(int, char *[]);
142
143static struct got_cmd got_commands[] = {
144 { "init", cmd_init, usage_init, "" },
145 { "import", cmd_import, usage_import, "im" },
146 { "clone", cmd_clone, usage_clone, "cl" },
147 { "fetch", cmd_fetch, usage_fetch, "fe" },
148 { "checkout", cmd_checkout, usage_checkout, "co" },
149 { "update", cmd_update, usage_update, "up" },
150 { "log", cmd_log, usage_log, "" },
151 { "diff", cmd_diff, usage_diff, "di" },
152 { "blame", cmd_blame, usage_blame, "bl" },
153 { "tree", cmd_tree, usage_tree, "tr" },
154 { "status", cmd_status, usage_status, "st" },
155 { "ref", cmd_ref, usage_ref, "" },
156 { "branch", cmd_branch, usage_branch, "br" },
157 { "tag", cmd_tag, usage_tag, "" },
158 { "add", cmd_add, usage_add, "" },
159 { "remove", cmd_remove, usage_remove, "rm" },
160 { "revert", cmd_revert, usage_revert, "rv" },
161 { "commit", cmd_commit, usage_commit, "ci" },
162 { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" },
163 { "backout", cmd_backout, usage_backout, "bo" },
164 { "rebase", cmd_rebase, usage_rebase, "rb" },
165 { "histedit", cmd_histedit, usage_histedit, "he" },
166 { "integrate", cmd_integrate, usage_integrate,"ig" },
167 { "stage", cmd_stage, usage_stage, "sg" },
168 { "unstage", cmd_unstage, usage_unstage, "ug" },
169 { "cat", cmd_cat, usage_cat, "" },
170 { "info", cmd_info, usage_info, "" },
171};
172
173static void
174list_commands(FILE *fp)
175{
176 size_t i;
177
178 fprintf(fp, "commands:");
179 for (i = 0; i < nitems(got_commands)(sizeof((got_commands)) / sizeof((got_commands)[0])); i++) {
180 struct got_cmd *cmd = &got_commands[i];
181 fprintf(fp, " %s", cmd->cmd_name);
182 }
183 fputc('\n', fp);
184}
185
186__dead__attribute__((__noreturn__)) static void
187option_conflict(char a, char b)
188{
189 errx(1, "-%c and -%c options are mutually exclusive", a, b);
190}
191
192int
193main(int argc, char *argv[])
194{
195 struct got_cmd *cmd;
196 size_t i;
197 int ch;
198 int hflag = 0, Vflag = 0;
199 static struct option longopts[] = {
200 { "version", no_argument0, NULL((void *)0), 'V' },
201 { NULL((void *)0), 0, NULL((void *)0), 0 }
202 };
203
204 setlocale(LC_CTYPE2, "");
205
206 while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL((void *)0))) != -1) {
207 switch (ch) {
208 case 'h':
209 hflag = 1;
210 break;
211 case 'V':
212 Vflag = 1;
213 break;
214 default:
215 usage(hflag, 1);
216 /* NOTREACHED */
217 }
218 }
219
220 argc -= optind;
221 argv += optind;
222 optind = 1;
223 optreset = 1;
224
225 if (Vflag) {
226 got_version_print_str();
227 return 0;
228 }
229
230 if (argc <= 0)
231 usage(hflag, hflag ? 0 : 1);
232
233 signal(SIGINT2, catch_sigint);
234 signal(SIGPIPE13, catch_sigpipe);
235
236 for (i = 0; i < nitems(got_commands)(sizeof((got_commands)) / sizeof((got_commands)[0])); i++) {
237 const struct got_error *error;
238
239 cmd = &got_commands[i];
240
241 if (strcmp(cmd->cmd_name, argv[0]) != 0 &&
242 strcmp(cmd->cmd_alias, argv[0]) != 0)
243 continue;
244
245 if (hflag)
246 got_commands[i].cmd_usage();
247
248 error = got_commands[i].cmd_main(argc, argv);
249 if (error && error->code != GOT_ERR_CANCELLED49 &&
250 error->code != GOT_ERR_PRIVSEP_EXIT41 &&
251 !(sigpipe_received &&
252 error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EPIPE32) &&
253 !(sigint_received &&
254 error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EINTR4)) {
255 fprintf(stderr(&__sF[2]), "%s: %s\n", getprogname(), error->msg);
256 return 1;
257 }
258
259 return 0;
260 }
261
262 fprintf(stderr(&__sF[2]), "%s: unknown command '%s'\n", getprogname(), argv[0]);
263 list_commands(stderr(&__sF[2]));
264 return 1;
265}
266
267__dead__attribute__((__noreturn__)) static void
268usage(int hflag, int status)
269{
270 FILE *fp = (status == 0) ? stdout(&__sF[1]) : stderr(&__sF[2]);
271
272 fprintf(fp, "usage: %s [-h] [-V | --version] command [arg ...]\n",
273 getprogname());
274 if (hflag)
275 list_commands(fp);
276 exit(status);
277}
278
279static const struct got_error *
280get_editor(char **abspath)
281{
282 const struct got_error *err = NULL((void *)0);
283 const char *editor;
284
285 *abspath = NULL((void *)0);
286
287 editor = getenv("VISUAL");
288 if (editor == NULL((void *)0))
289 editor = getenv("EDITOR");
290
291 if (editor) {
292 err = got_path_find_prog(abspath, editor);
293 if (err)
294 return err;
295 }
296
297 if (*abspath == NULL((void *)0)) {
298 *abspath = strdup("/bin/ed");
299 if (*abspath == NULL((void *)0))
300 return got_error_from_errno("strdup");
301 }
302
303 return NULL((void *)0);
304}
305
306static const struct got_error *
307apply_unveil(const char *repo_path, int repo_read_only,
308 const char *worktree_path)
309{
310 const struct got_error *err;
311
312#ifdef PROFILE
313 if (unveil("gmon.out", "rwc") != 0)
314 return got_error_from_errno2("unveil", "gmon.out");
315#endif
316 if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0)
317 return got_error_from_errno2("unveil", repo_path);
318
319 if (worktree_path && unveil(worktree_path, "rwc") != 0)
320 return got_error_from_errno2("unveil", worktree_path);
321
322 if (unveil(GOT_TMPDIR_STR"/tmp", "rwc") != 0)
323 return got_error_from_errno2("unveil", GOT_TMPDIR_STR"/tmp");
324
325 err = got_privsep_unveil_exec_helpers();
326 if (err != NULL((void *)0))
327 return err;
328
329 if (unveil(NULL((void *)0), NULL((void *)0)) != 0)
330 return got_error_from_errno("unveil");
331
332 return NULL((void *)0);
333}
334
335__dead__attribute__((__noreturn__)) static void
336usage_init(void)
337{
338 fprintf(stderr(&__sF[2]), "usage: %s init repository-path\n", getprogname());
339 exit(1);
340}
341
342static const struct got_error *
343cmd_init(int argc, char *argv[])
344{
345 const struct got_error *error = NULL((void *)0);
346 char *repo_path = NULL((void *)0);
347 int ch;
348
349 while ((ch = getopt(argc, argv, "")) != -1) {
350 switch (ch) {
351 default:
352 usage_init();
353 /* NOTREACHED */
354 }
355 }
356
357 argc -= optind;
358 argv += optind;
359
360#ifndef PROFILE
361 if (pledge("stdio rpath wpath cpath unveil", NULL((void *)0)) == -1)
362 err(1, "pledge");
363#endif
364 if (argc != 1)
365 usage_init();
366
367 repo_path = strdup(argv[0]);
368 if (repo_path == NULL((void *)0))
369 return got_error_from_errno("strdup");
370
371 got_path_strip_trailing_slashes(repo_path);
372
373 error = got_path_mkdir(repo_path);
374 if (error &&
375 !(error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EEXIST17))
376 goto done;
377
378 error = apply_unveil(repo_path, 0, NULL((void *)0));
379 if (error)
380 goto done;
381
382 error = got_repo_init(repo_path);
383done:
384 free(repo_path);
385 return error;
386}
387
388__dead__attribute__((__noreturn__)) static void
389usage_import(void)
390{
391 fprintf(stderr(&__sF[2]), "usage: %s import [-b branch] [-m message] "
392 "[-r repository-path] [-I pattern] path\n", getprogname());
393 exit(1);
394}
395
396int
397spawn_editor(const char *editor, const char *file)
398{
399 pid_t pid;
400 sig_t sighup, sigint, sigquit;
401 int st = -1;
402
403 sighup = signal(SIGHUP1, SIG_IGN(void (*)(int))1);
404 sigint = signal(SIGINT2, SIG_IGN(void (*)(int))1);
405 sigquit = signal(SIGQUIT3, SIG_IGN(void (*)(int))1);
406
407 switch (pid = fork()) {
408 case -1:
409 goto doneediting;
410 case 0:
411 execl(editor, editor, file, (char *)NULL((void *)0));
412 _exit(127);
413 }
414
415 while (waitpid(pid, &st, 0) == -1)
416 if (errno(*__errno()) != EINTR4)
417 break;
418
419doneediting:
420 (void)signal(SIGHUP1, sighup);
421 (void)signal(SIGINT2, sigint);
422 (void)signal(SIGQUIT3, sigquit);
423
424 if (!WIFEXITED(st)(((st) & 0177) == 0)) {
425 errno(*__errno()) = EINTR4;
426 return -1;
427 }
428
429 return WEXITSTATUS(st)(int)(((unsigned)(st) >> 8) & 0xff);
430}
431
432static const struct got_error *
433edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path,
434 const char *initial_content, size_t initial_content_len,
435 int require_modification)
436{
437 const struct got_error *err = NULL((void *)0);
438 char *line = NULL((void *)0);
439 size_t linesize = 0;
440 ssize_t linelen;
441 struct stat st, st2;
442 FILE *fp = NULL((void *)0);
443 size_t len, logmsg_len;
444 char *initial_content_stripped = NULL((void *)0), *buf = NULL((void *)0), *s;
445
446 *logmsg = NULL((void *)0);
447
448 if (stat(logmsg_path, &st) == -1)
449 return got_error_from_errno2("stat", logmsg_path);
450
451 if (spawn_editor(editor, logmsg_path) == -1)
452 return got_error_from_errno("failed spawning editor");
453
454 if (stat(logmsg_path, &st2) == -1)
455 return got_error_from_errno("stat");
456
457 if (require_modification &&
458 st.st_mtimest_mtim.tv_sec == st2.st_mtimest_mtim.tv_sec && st.st_size == st2.st_size)
459 return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY74,
460 "no changes made to commit message, aborting");
461
462 /*
463 * Set up a stripped version of the initial content without comments
464 * and blank lines. We need this in order to check if the message
465 * has in fact been edited.
466 */
467 initial_content_stripped = malloc(initial_content_len + 1);
468 if (initial_content_stripped == NULL((void *)0))
469 return got_error_from_errno("malloc");
470 initial_content_stripped[0] = '\0';
471
472 buf = strdup(initial_content);
473 if (buf == NULL((void *)0)) {
474 err = got_error_from_errno("strdup");
475 goto done;
476 }
477 s = buf;
478 len = 0;
479 while ((line = strsep(&s, "\n")) != NULL((void *)0)) {
480 if ((line[0] == '#' || (len == 0 && line[0] == '\n')))
481 continue; /* remove comments and leading empty lines */
482 len = strlcat(initial_content_stripped, line,
483 initial_content_len + 1);
484 if (len >= initial_content_len + 1) {
485 err = got_error(GOT_ERR_NO_SPACE9);
486 goto done;
487 }
488 }
489 while (len > 0 && initial_content_stripped[len - 1] == '\n') {
490 initial_content_stripped[len - 1] = '\0';
491 len--;
492 }
493
494 logmsg_len = st2.st_size;
495 *logmsg = malloc(logmsg_len + 1);
496 if (*logmsg == NULL((void *)0))
497 return got_error_from_errno("malloc");
498 (*logmsg)[0] = '\0';
499
500 fp = fopen(logmsg_path, "r");
501 if (fp == NULL((void *)0)) {
502 err = got_error_from_errno("fopen");
503 goto done;
504 }
505
506 len = 0;
507 while ((linelen = getline(&line, &linesize, fp)) != -1) {
Although the value stored to 'linelen' is used in the enclosing expression, the value is never actually read from 'linelen'
508 if ((line[0] == '#' || (len == 0 && line[0] == '\n')))
509 continue; /* remove comments and leading empty lines */
510 len = strlcat(*logmsg, line, logmsg_len + 1);
511 if (len >= logmsg_len + 1) {
512 err = got_error(GOT_ERR_NO_SPACE9);
513 goto done;
514 }
515 }
516 free(line);
517 if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
) {
518 err = got_ferror(fp, GOT_ERR_IO6);
519 goto done;
520 }
521 while (len > 0 && (*logmsg)[len - 1] == '\n') {
522 (*logmsg)[len - 1] = '\0';
523 len--;
524 }
525
526 if (len == 0) {
527 err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY74,
528 "commit message cannot be empty, aborting");
529 goto done;
530 }
531 if (require_modification &&
532 strcmp(*logmsg, initial_content_stripped) == 0)
533 err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY74,
534 "no changes made to commit message, aborting");
535done:
536 free(initial_content_stripped);
537 free(buf);
538 if (fp && fclose(fp) == EOF(-1) && err == NULL((void *)0))
539 err = got_error_from_errno("fclose");
540 if (err) {
541 free(*logmsg);
542 *logmsg = NULL((void *)0);
543 }
544 return err;
545}
546
547static const struct got_error *
548collect_import_msg(char **logmsg, char **logmsg_path, const char *editor,
549 const char *path_dir, const char *branch_name)
550{
551 char *initial_content = NULL((void *)0);
552 const struct got_error *err = NULL((void *)0);
553 int initial_content_len;
554 int fd = -1;
555
556 initial_content_len = asprintf(&initial_content,
557 "\n# %s to be imported to branch %s\n", path_dir,
558 branch_name);
559 if (initial_content_len == -1)
560 return got_error_from_errno("asprintf");
561
562 err = got_opentemp_named_fd(logmsg_path, &fd,
563 GOT_TMPDIR_STR"/tmp" "/got-importmsg");
564 if (err)
565 goto done;
566
567 if (write(fd, initial_content, initial_content_len) == -1) {
568 err = got_error_from_errno2("write", *logmsg_path);
569 goto done;
570 }
571
572 err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content,
573 initial_content_len, 1);
574done:
575 if (fd != -1 && close(fd) == -1 && err == NULL((void *)0))
576 err = got_error_from_errno2("close", *logmsg_path);
577 free(initial_content);
578 if (err) {
579 free(*logmsg_path);
580 *logmsg_path = NULL((void *)0);
581 }
582 return err;
583}
584
585static const struct got_error *
586import_progress(void *arg, const char *path)
587{
588 printf("A %s\n", path);
589 return NULL((void *)0);
590}
591
592static const struct got_error *
593get_author(char **author, struct got_repository *repo,
594 struct got_worktree *worktree)
595{
596 const struct got_error *err = NULL((void *)0);
597 const char *got_author = NULL((void *)0), *name, *email;
598 const struct got_gotconfig *worktree_conf = NULL((void *)0), *repo_conf = NULL((void *)0);
599
600 *author = NULL((void *)0);
601
602 if (worktree)
603 worktree_conf = got_worktree_get_gotconfig(worktree);
604 repo_conf = got_repo_get_gotconfig(repo);
605
606 /*
607 * Priority of potential author information sources, from most
608 * significant to least significant:
609 * 1) work tree's .got/got.conf file
610 * 2) repository's got.conf file
611 * 3) repository's git config file
612 * 4) environment variables
613 * 5) global git config files (in user's home directory or /etc)
614 */
615
616 if (worktree_conf)
617 got_author = got_gotconfig_get_author(worktree_conf);
618 if (got_author == NULL((void *)0))
619 got_author = got_gotconfig_get_author(repo_conf);
620 if (got_author == NULL((void *)0)) {
621 name = got_repo_get_gitconfig_author_name(repo);
622 email = got_repo_get_gitconfig_author_email(repo);
623 if (name && email) {
624 if (asprintf(author, "%s <%s>", name, email) == -1)
625 return got_error_from_errno("asprintf");
626 return NULL((void *)0);
627 }
628
629 got_author = getenv("GOT_AUTHOR");
630 if (got_author == NULL((void *)0)) {
631 name = got_repo_get_global_gitconfig_author_name(repo);
632 email = got_repo_get_global_gitconfig_author_email(
633 repo);
634 if (name && email) {
635 if (asprintf(author, "%s <%s>", name, email)
636 == -1)
637 return got_error_from_errno("asprintf");
638 return NULL((void *)0);
639 }
640 /* TODO: Look up user in password database? */
641 return got_error(GOT_ERR_COMMIT_NO_AUTHOR71);
642 }
643 }
644
645 *author = strdup(got_author);
646 if (*author == NULL((void *)0))
647 return got_error_from_errno("strdup");
648
649 /*
650 * Really dumb email address check; we're only doing this to
651 * avoid git's object parser breaking on commits we create.
652 */
653 while (*got_author && *got_author != '<')
654 got_author++;
655 if (*got_author != '<') {
656 err = got_error(GOT_ERR_COMMIT_NO_EMAIL108);
657 goto done;
658 }
659 while (*got_author && *got_author != '@')
660 got_author++;
661 if (*got_author != '@') {
662 err = got_error(GOT_ERR_COMMIT_NO_EMAIL108);
663 goto done;
664 }
665 while (*got_author && *got_author != '>')
666 got_author++;
667 if (*got_author != '>')
668 err = got_error(GOT_ERR_COMMIT_NO_EMAIL108);
669done:
670 if (err) {
671 free(*author);
672 *author = NULL((void *)0);
673 }
674 return err;
675}
676
677static const struct got_error *
678get_gitconfig_path(char **gitconfig_path)
679{
680 const char *homedir = getenv("HOME");
681
682 *gitconfig_path = NULL((void *)0);
683 if (homedir) {
684 if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1)
685 return got_error_from_errno("asprintf");
686
687 }
688 return NULL((void *)0);
689}
690
691static const struct got_error *
692cmd_import(int argc, char *argv[])
693{
694 const struct got_error *error = NULL((void *)0);
695 char *path_dir = NULL((void *)0), *repo_path = NULL((void *)0), *logmsg = NULL((void *)0);
696 char *gitconfig_path = NULL((void *)0), *editor = NULL((void *)0), *author = NULL((void *)0);
697 const char *branch_name = "main";
698 char *refname = NULL((void *)0), *id_str = NULL((void *)0), *logmsg_path = NULL((void *)0);
699 struct got_repository *repo = NULL((void *)0);
700 struct got_reference *branch_ref = NULL((void *)0), *head_ref = NULL((void *)0);
701 struct got_object_id *new_commit_id = NULL((void *)0);
702 int ch;
703 struct got_pathlist_head ignores;
704 struct got_pathlist_entry *pe;
705 int preserve_logmsg = 0;
706
707 TAILQ_INIT(&ignores)do { (&ignores)->tqh_first = ((void *)0); (&ignores
)->tqh_last = &(&ignores)->tqh_first; } while (
0)
;
708
709 while ((ch = getopt(argc, argv, "b:m:r:I:")) != -1) {
710 switch (ch) {
711 case 'b':
712 branch_name = optarg;
713 break;
714 case 'm':
715 logmsg = strdup(optarg);
716 if (logmsg == NULL((void *)0)) {
717 error = got_error_from_errno("strdup");
718 goto done;
719 }
720 break;
721 case 'r':
722 repo_path = realpath(optarg, NULL((void *)0));
723 if (repo_path == NULL((void *)0)) {
724 error = got_error_from_errno2("realpath",
725 optarg);
726 goto done;
727 }
728 break;
729 case 'I':
730 if (optarg[0] == '\0')
731 break;
732 error = got_pathlist_insert(&pe, &ignores, optarg,
733 NULL((void *)0));
734 if (error)
735 goto done;
736 break;
737 default:
738 usage_import();
739 /* NOTREACHED */
740 }
741 }
742
743 argc -= optind;
744 argv += optind;
745
746#ifndef PROFILE
747 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
748 "unveil",
749 NULL((void *)0)) == -1)
750 err(1, "pledge");
751#endif
752 if (argc != 1)
753 usage_import();
754
755 if (repo_path == NULL((void *)0)) {
756 repo_path = getcwd(NULL((void *)0), 0);
757 if (repo_path == NULL((void *)0))
758 return got_error_from_errno("getcwd");
759 }
760 got_path_strip_trailing_slashes(repo_path);
761 error = get_gitconfig_path(&gitconfig_path);
762 if (error)
763 goto done;
764 error = got_repo_open(&repo, repo_path, gitconfig_path);
765 if (error)
766 goto done;
767
768 error = get_author(&author, repo, NULL((void *)0));
769 if (error)
770 return error;
771
772 /*
773 * Don't let the user create a branch name with a leading '-'.
774 * While technically a valid reference name, this case is usually
775 * an unintended typo.
776 */
777 if (branch_name[0] == '-')
778 return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS113);
779
780 if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
781 error = got_error_from_errno("asprintf");
782 goto done;
783 }
784
785 error = got_ref_open(&branch_ref, repo, refname, 0);
786 if (error) {
787 if (error->code != GOT_ERR_NOT_REF5)
788 goto done;
789 } else {
790 error = got_error_msg(GOT_ERR_BRANCH_EXISTS83,
791 "import target branch already exists");
792 goto done;
793 }
794
795 path_dir = realpath(argv[0], NULL((void *)0));
796 if (path_dir == NULL((void *)0)) {
797 error = got_error_from_errno2("realpath", argv[0]);
798 goto done;
799 }
800 got_path_strip_trailing_slashes(path_dir);
801
802 /*
803 * unveil(2) traverses exec(2); if an editor is used we have
804 * to apply unveil after the log message has been written.
805 */
806 if (logmsg == NULL((void *)0) || strlen(logmsg) == 0) {
807 error = get_editor(&editor);
808 if (error)
809 goto done;
810 free(logmsg);
811 error = collect_import_msg(&logmsg, &logmsg_path, editor,
812 path_dir, refname);
813 if (error) {
814 if (error->code != GOT_ERR_COMMIT_MSG_EMPTY74 &&
815 logmsg_path != NULL((void *)0))
816 preserve_logmsg = 1;
817 goto done;
818 }
819 }
820
821 if (unveil(path_dir, "r") != 0) {
822 error = got_error_from_errno2("unveil", path_dir);
823 if (logmsg_path)
824 preserve_logmsg = 1;
825 goto done;
826 }
827
828 error = apply_unveil(got_repo_get_path(repo), 0, NULL((void *)0));
829 if (error) {
830 if (logmsg_path)
831 preserve_logmsg = 1;
832 goto done;
833 }
834
835 error = got_repo_import(&new_commit_id, path_dir, logmsg,
836 author, &ignores, repo, import_progress, NULL((void *)0));
837 if (error) {
838 if (logmsg_path)
839 preserve_logmsg = 1;
840 goto done;
841 }
842
843 error = got_ref_alloc(&branch_ref, refname, new_commit_id);
844 if (error) {
845 if (logmsg_path)
846 preserve_logmsg = 1;
847 goto done;
848 }
849
850 error = got_ref_write(branch_ref, repo);
851 if (error) {
852 if (logmsg_path)
853 preserve_logmsg = 1;
854 goto done;
855 }
856
857 error = got_object_id_str(&id_str, new_commit_id);
858 if (error) {
859 if (logmsg_path)
860 preserve_logmsg = 1;
861 goto done;
862 }
863
864 error = got_ref_open(&head_ref, repo, GOT_REF_HEAD"HEAD", 0);
865 if (error) {
866 if (error->code != GOT_ERR_NOT_REF5) {
867 if (logmsg_path)
868 preserve_logmsg = 1;
869 goto done;
870 }
871
872 error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD"HEAD",
873 branch_ref);
874 if (error) {
875 if (logmsg_path)
876 preserve_logmsg = 1;
877 goto done;
878 }
879
880 error = got_ref_write(head_ref, repo);
881 if (error) {
882 if (logmsg_path)
883 preserve_logmsg = 1;
884 goto done;
885 }
886 }
887
888 printf("Created branch %s with commit %s\n",
889 got_ref_get_name(branch_ref), id_str);
890done:
891 if (preserve_logmsg) {
892 fprintf(stderr(&__sF[2]), "%s: log message preserved in %s\n",
893 getprogname(), logmsg_path);
894 } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL((void *)0))
895 error = got_error_from_errno2("unlink", logmsg_path);
896 free(logmsg);
897 free(logmsg_path);
898 free(repo_path);
899 free(editor);
900 free(refname);
901 free(new_commit_id);
902 free(id_str);
903 free(author);
904 free(gitconfig_path);
905 if (branch_ref)
906 got_ref_close(branch_ref);
907 if (head_ref)
908 got_ref_close(head_ref);
909 return error;
910}
911
912__dead__attribute__((__noreturn__)) static void
913usage_clone(void)
914{
915 fprintf(stderr(&__sF[2]), "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
916 "[-R reference] repository-url [directory]\n", getprogname());
917 exit(1);
918}
919
920struct got_fetch_progress_arg {
921 char last_scaled_size[FMT_SCALED_STRSIZE7];
922 int last_p_indexed;
923 int last_p_resolved;
924 int verbosity;
925
926 struct got_repository *repo;
927
928 int create_configs;
929 int configs_created;
930 struct {
931 struct got_pathlist_head *symrefs;
932 struct got_pathlist_head *wanted_branches;
933 struct got_pathlist_head *wanted_refs;
934 const char *proto;
935 const char *host;
936 const char *port;
937 const char *remote_repo_path;
938 const char *git_url;
939 int fetch_all_branches;
940 int mirror_references;
941 } config_info;
942};
943
944/* XXX forward declaration */
945static const struct got_error *
946create_config_files(const char *proto, const char *host, const char *port,
947 const char *remote_repo_path, const char *git_url, int fetch_all_branches,
948 int mirror_references, struct got_pathlist_head *symrefs,
949 struct got_pathlist_head *wanted_branches,
950 struct got_pathlist_head *wanted_refs, struct got_repository *repo);
951
952static const struct got_error *
953fetch_progress(void *arg, const char *message, off_t packfile_size,
954 int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved)
955{
956 const struct got_error *err = NULL((void *)0);
957 struct got_fetch_progress_arg *a = arg;
958 char scaled_size[FMT_SCALED_STRSIZE7];
959 int p_indexed, p_resolved;
960 int print_size = 0, print_indexed = 0, print_resolved = 0;
961
962 /*
963 * In order to allow a failed clone to be resumed with 'got fetch'
964 * we try to create configuration files as soon as possible.
965 * Once the server has sent information about its default branch
966 * we have all required information.
967 */
968 if (a->create_configs && !a->configs_created &&
969 !TAILQ_EMPTY(a->config_info.symrefs)(((a->config_info.symrefs)->tqh_first) == ((void *)0))) {
970 err = create_config_files(a->config_info.proto,
971 a->config_info.host, a->config_info.port,
972 a->config_info.remote_repo_path,
973 a->config_info.git_url,
974 a->config_info.fetch_all_branches,
975 a->config_info.mirror_references,
976 a->config_info.symrefs,
977 a->config_info.wanted_branches,
978 a->config_info.wanted_refs, a->repo);
979 if (err)
980 return err;
981 a->configs_created = 1;
982 }
983
984 if (a->verbosity < 0)
985 return NULL((void *)0);
986
987 if (message && message[0] != '\0') {
988 printf("\rserver: %s", message);
989 fflush(stdout(&__sF[1]));
990 return NULL((void *)0);
991 }
992
993 if (packfile_size > 0 || nobj_indexed > 0) {
994 if (fmt_scaled(packfile_size, scaled_size) == 0 &&
995 (a->last_scaled_size[0] == '\0' ||
996 strcmp(scaled_size, a->last_scaled_size)) != 0) {
997 print_size = 1;
998 if (strlcpy(a->last_scaled_size, scaled_size,
999 FMT_SCALED_STRSIZE7) >= FMT_SCALED_STRSIZE7)
1000 return got_error(GOT_ERR_NO_SPACE9);
1001 }
1002 if (nobj_indexed > 0) {
1003 p_indexed = (nobj_indexed * 100) / nobj_total;
1004 if (p_indexed != a->last_p_indexed) {
1005 a->last_p_indexed = p_indexed;
1006 print_indexed = 1;
1007 print_size = 1;
1008 }
1009 }
1010 if (nobj_resolved > 0) {
1011 p_resolved = (nobj_resolved * 100) /
1012 (nobj_total - nobj_loose);
1013 if (p_resolved != a->last_p_resolved) {
1014 a->last_p_resolved = p_resolved;
1015 print_resolved = 1;
1016 print_indexed = 1;
1017 print_size = 1;
1018 }
1019 }
1020
1021 }
1022 if (print_size || print_indexed || print_resolved)
1023 printf("\r");
1024 if (print_size)
1025 printf("%*s fetched", FMT_SCALED_STRSIZE7, scaled_size);
1026 if (print_indexed)
1027 printf("; indexing %d%%", p_indexed);
1028 if (print_resolved)
1029 printf("; resolving deltas %d%%", p_resolved);
1030 if (print_size || print_indexed || print_resolved)
1031 fflush(stdout(&__sF[1]));
1032
1033 return NULL((void *)0);
1034}
1035
1036static const struct got_error *
1037create_symref(const char *refname, struct got_reference *target_ref,
1038 int verbosity, struct got_repository *repo)
1039{
1040 const struct got_error *err;
1041 struct got_reference *head_symref;
1042
1043 err = got_ref_alloc_symref(&head_symref, refname, target_ref);
1044 if (err)
1045 return err;
1046
1047 err = got_ref_write(head_symref, repo);
1048 if (err == NULL((void *)0) && verbosity > 0) {
1049 printf("Created reference %s: %s\n", GOT_REF_HEAD"HEAD",
1050 got_ref_get_name(target_ref));
1051 }
1052 got_ref_close(head_symref);
1053 return err;
1054}
1055
1056static const struct got_error *
1057list_remote_refs(struct got_pathlist_head *symrefs,
1058 struct got_pathlist_head *refs)
1059{
1060 const struct got_error *err;
1061 struct got_pathlist_entry *pe;
1062
1063 TAILQ_FOREACH(pe, symrefs, entry)for((pe) = ((symrefs)->tqh_first); (pe) != ((void *)0); (pe
) = ((pe)->entry.tqe_next))
{
1064 const char *refname = pe->path;
1065 const char *targetref = pe->data;
1066
1067 printf("%s: %s\n", refname, targetref);
1068 }
1069
1070 TAILQ_FOREACH(pe, refs, entry)for((pe) = ((refs)->tqh_first); (pe) != ((void *)0); (pe) =
((pe)->entry.tqe_next))
{
1071 const char *refname = pe->path;
1072 struct got_object_id *id = pe->data;
1073 char *id_str;
1074
1075 err = got_object_id_str(&id_str, id);
1076 if (err)
1077 return err;
1078 printf("%s: %s\n", refname, id_str);
1079 free(id_str);
1080 }
1081
1082 return NULL((void *)0);
1083}
1084
1085static const struct got_error *
1086create_ref(const char *refname, struct got_object_id *id,
1087 int verbosity, struct got_repository *repo)
1088{
1089 const struct got_error *err = NULL((void *)0);
1090 struct got_reference *ref;
1091 char *id_str;
1092
1093 err = got_object_id_str(&id_str, id);
1094 if (err)
1095 return err;
1096
1097 err = got_ref_alloc(&ref, refname, id);
1098 if (err)
1099 goto done;
1100
1101 err = got_ref_write(ref, repo);
1102 got_ref_close(ref);
1103
1104 if (err == NULL((void *)0) && verbosity >= 0)
1105 printf("Created reference %s: %s\n", refname, id_str);
1106done:
1107 free(id_str);
1108 return err;
1109}
1110
1111static int
1112match_wanted_ref(const char *refname, const char *wanted_ref)
1113{
1114 if (strncmp(refname, "refs/", 5) != 0)
1115 return 0;
1116 refname += 5;
1117
1118 /*
1119 * Prevent fetching of references that won't make any
1120 * sense outside of the remote repository's context.
1121 */
1122 if (strncmp(refname, "got/", 4) == 0)
1123 return 0;
1124 if (strncmp(refname, "remotes/", 8) == 0)
1125 return 0;
1126
1127 if (strncmp(wanted_ref, "refs/", 5) == 0)
1128 wanted_ref += 5;
1129
1130 /* Allow prefix match. */
1131 if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
1132 return 1;
1133
1134 /* Allow exact match. */
1135 return (strcmp(refname, wanted_ref) == 0);
1136}
1137
1138static int
1139is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
1140{
1141 struct got_pathlist_entry *pe;
1142
1143 TAILQ_FOREACH(pe, wanted_refs, entry)for((pe) = ((wanted_refs)->tqh_first); (pe) != ((void *)0)
; (pe) = ((pe)->entry.tqe_next))
{
1144 if (match_wanted_ref(refname, pe->path))
1145 return 1;
1146 }
1147
1148 return 0;
1149}
1150
1151static const struct got_error *
1152create_wanted_ref(const char *refname, struct got_object_id *id,
1153 const char *remote_repo_name, int verbosity, struct got_repository *repo)
1154{
1155 const struct got_error *err;
1156 char *remote_refname;
1157
1158 if (strncmp("refs/", refname, 5) == 0)
1159 refname += 5;
1160
1161 if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1162 remote_repo_name, refname) == -1)
1163 return got_error_from_errno("asprintf");
1164
1165 err = create_ref(remote_refname, id, verbosity, repo);
1166 free(remote_refname);
1167 return err;
1168}
1169
1170static const struct got_error *
1171create_gotconfig(const char *proto, const char *host, const char *port,
1172 const char *remote_repo_path, const char *default_branch,
1173 int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1174 struct got_pathlist_head *wanted_refs, int mirror_references,
1175 struct got_repository *repo)
1176{
1177 const struct got_error *err = NULL((void *)0);
1178 char *gotconfig_path = NULL((void *)0);
1179 char *gotconfig = NULL((void *)0);
1180 FILE *gotconfig_file = NULL((void *)0);
1181 const char *branchname = NULL((void *)0);
1182 char *branches = NULL((void *)0), *refs = NULL((void *)0);
1183 ssize_t n;
1184
1185 if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)(((wanted_branches)->tqh_first) == ((void *)0))) {
1186 struct got_pathlist_entry *pe;
1187 TAILQ_FOREACH(pe, wanted_branches, entry)for((pe) = ((wanted_branches)->tqh_first); (pe) != ((void *
)0); (pe) = ((pe)->entry.tqe_next))
{
1188 char *s;
1189 branchname = pe->path;
1190 if (strncmp(branchname, "refs/heads/", 11) == 0)
1191 branchname += 11;
1192 if (asprintf(&s, "%s\"%s\" ",
1193 branches ? branches : "", branchname) == -1) {
1194 err = got_error_from_errno("asprintf");
1195 goto done;
1196 }
1197 free(branches);
1198 branches = s;
1199 }
1200 } else if (!fetch_all_branches && default_branch) {
1201 branchname = default_branch;
1202 if (strncmp(branchname, "refs/heads/", 11) == 0)
1203 branchname += 11;
1204 if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
1205 err = got_error_from_errno("asprintf");
1206 goto done;
1207 }
1208 }
1209 if (!TAILQ_EMPTY(wanted_refs)(((wanted_refs)->tqh_first) == ((void *)0))) {
1210 struct got_pathlist_entry *pe;
1211 TAILQ_FOREACH(pe, wanted_refs, entry)for((pe) = ((wanted_refs)->tqh_first); (pe) != ((void *)0)
; (pe) = ((pe)->entry.tqe_next))
{
1212 char *s;
1213 const char *refname = pe->path;
1214 if (strncmp(refname, "refs/", 5) == 0)
1215 branchname += 5;
1216 if (asprintf(&s, "%s\"%s\" ",
1217 refs ? refs : "", refname) == -1) {
1218 err = got_error_from_errno("asprintf");
1219 goto done;
1220 }
1221 free(refs);
1222 refs = s;
1223 }
1224 }
1225
1226 /* Create got.conf(5). */
1227 gotconfig_path = got_repo_get_path_gotconfig(repo);
1228 if (gotconfig_path == NULL((void *)0)) {
1229 err = got_error_from_errno("got_repo_get_path_gotconfig");
1230 goto done;
1231 }
1232 gotconfig_file = fopen(gotconfig_path, "a");
1233 if (gotconfig_file == NULL((void *)0)) {
1234 err = got_error_from_errno2("fopen", gotconfig_path);
1235 goto done;
1236 }
1237 if (asprintf(&gotconfig,
1238 "remote \"%s\" {\n"
1239 "\tserver %s\n"
1240 "\tprotocol %s\n"
1241 "%s%s%s"
1242 "\trepository \"%s\"\n"
1243 "%s%s%s"
1244 "%s%s%s"
1245 "%s"
1246 "%s"
1247 "}\n",
1248 GOT_FETCH_DEFAULT_REMOTE_NAME"origin", host, proto,
1249 port ? "\tport " : "", port ? port : "", port ? "\n" : "",
1250 remote_repo_path, branches ? "\tbranch { " : "",
1251 branches ? branches : "", branches ? "}\n" : "",
1252 refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "",
1253 mirror_references ? "\tmirror-references yes\n" : "",
1254 fetch_all_branches ? "\tfetch-all-branches yes\n" : "") == -1) {
1255 err = got_error_from_errno("asprintf");
1256 goto done;
1257 }
1258 n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
1259 if (n != strlen(gotconfig)) {
1260 err = got_ferror(gotconfig_file, GOT_ERR_IO6);
1261 goto done;
1262 }
1263
1264done:
1265 if (gotconfig_file && fclose(gotconfig_file) == EOF(-1) && err == NULL((void *)0))
1266 err = got_error_from_errno2("fclose", gotconfig_path);
1267 free(gotconfig_path);
1268 free(branches);
1269 return err;
1270}
1271
1272static const struct got_error *
1273create_gitconfig(const char *git_url, const char *default_branch,
1274 int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1275 struct got_pathlist_head *wanted_refs, int mirror_references,
1276 struct got_repository *repo)
1277{
1278 const struct got_error *err = NULL((void *)0);
1279 char *gitconfig_path = NULL((void *)0);
1280 char *gitconfig = NULL((void *)0);
1281 FILE *gitconfig_file = NULL((void *)0);
1282 char *branches = NULL((void *)0), *refs = NULL((void *)0);
1283 const char *branchname;
1284 ssize_t n;
1285
1286 /* Create a config file Git can understand. */
1287 gitconfig_path = got_repo_get_path_gitconfig(repo);
1288 if (gitconfig_path == NULL((void *)0)) {
1289 err = got_error_from_errno("got_repo_get_path_gitconfig");
1290 goto done;
1291 }
1292 gitconfig_file = fopen(gitconfig_path, "a");
1293 if (gitconfig_file == NULL((void *)0)) {
1294 err = got_error_from_errno2("fopen", gitconfig_path);
1295 goto done;
1296 }
1297 if (fetch_all_branches) {
1298 if (mirror_references) {
1299 if (asprintf(&branches,
1300 "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1301 err = got_error_from_errno("asprintf");
1302 goto done;
1303 }
1304 } else if (asprintf(&branches,
1305 "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1306 GOT_FETCH_DEFAULT_REMOTE_NAME"origin") == -1) {
1307 err = got_error_from_errno("asprintf");
1308 goto done;
1309 }
1310 } else if (!TAILQ_EMPTY(wanted_branches)(((wanted_branches)->tqh_first) == ((void *)0))) {
1311 struct got_pathlist_entry *pe;
1312 TAILQ_FOREACH(pe, wanted_branches, entry)for((pe) = ((wanted_branches)->tqh_first); (pe) != ((void *
)0); (pe) = ((pe)->entry.tqe_next))
{
1313 char *s;
1314 branchname = pe->path;
1315 if (strncmp(branchname, "refs/heads/", 11) == 0)
1316 branchname += 11;
1317 if (mirror_references) {
1318 if (asprintf(&s,
1319 "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1320 branches ? branches : "",
1321 branchname, branchname) == -1) {
1322 err = got_error_from_errno("asprintf");
1323 goto done;
1324 }
1325 } else if (asprintf(&s,
1326 "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1327 branches ? branches : "",
1328 branchname, GOT_FETCH_DEFAULT_REMOTE_NAME"origin",
1329 branchname) == -1) {
1330 err = got_error_from_errno("asprintf");
1331 goto done;
1332 }
1333 free(branches);
1334 branches = s;
1335 }
1336 } else {
1337 /*
1338 * If the server specified a default branch, use just that one.
1339 * Otherwise fall back to fetching all branches on next fetch.
1340 */
1341 if (default_branch) {
1342 branchname = default_branch;
1343 if (strncmp(branchname, "refs/heads/", 11) == 0)
1344 branchname += 11;
1345 } else
1346 branchname = "*"; /* fall back to all branches */
1347 if (mirror_references) {
1348 if (asprintf(&branches,
1349 "\tfetch = refs/heads/%s:refs/heads/%s\n",
1350 branchname, branchname) == -1) {
1351 err = got_error_from_errno("asprintf");
1352 goto done;
1353 }
1354 } else if (asprintf(&branches,
1355 "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1356 branchname, GOT_FETCH_DEFAULT_REMOTE_NAME"origin",
1357 branchname) == -1) {
1358 err = got_error_from_errno("asprintf");
1359 goto done;
1360 }
1361 }
1362 if (!TAILQ_EMPTY(wanted_refs)(((wanted_refs)->tqh_first) == ((void *)0))) {
1363 struct got_pathlist_entry *pe;
1364 TAILQ_FOREACH(pe, wanted_refs, entry)for((pe) = ((wanted_refs)->tqh_first); (pe) != ((void *)0)
; (pe) = ((pe)->entry.tqe_next))
{
1365 char *s;
1366 const char *refname = pe->path;
1367 if (strncmp(refname, "refs/", 5) == 0)
1368 refname += 5;
1369 if (mirror_references) {
1370 if (asprintf(&s,
1371 "%s\tfetch = refs/%s:refs/%s\n",
1372 refs ? refs : "", refname, refname) == -1) {
1373 err = got_error_from_errno("asprintf");
1374 goto done;
1375 }
1376 } else if (asprintf(&s,
1377 "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1378 refs ? refs : "",
1379 refname, GOT_FETCH_DEFAULT_REMOTE_NAME"origin",
1380 refname) == -1) {
1381 err = got_error_from_errno("asprintf");
1382 goto done;
1383 }
1384 free(refs);
1385 refs = s;
1386 }
1387 }
1388
1389 if (asprintf(&gitconfig,
1390 "[remote \"%s\"]\n"
1391 "\turl = %s\n"
1392 "%s"
1393 "%s"
1394 "\tfetch = refs/tags/*:refs/tags/*\n",
1395 GOT_FETCH_DEFAULT_REMOTE_NAME"origin", git_url, branches ? branches : "",
1396 refs ? refs : "") == -1) {
1397 err = got_error_from_errno("asprintf");
1398 goto done;
1399 }
1400 n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
1401 if (n != strlen(gitconfig)) {
1402 err = got_ferror(gitconfig_file, GOT_ERR_IO6);
1403 goto done;
1404 }
1405done:
1406 if (gitconfig_file && fclose(gitconfig_file) == EOF(-1) && err == NULL((void *)0))
1407 err = got_error_from_errno2("fclose", gitconfig_path);
1408 free(gitconfig_path);
1409 free(branches);
1410 return err;
1411}
1412
1413static const struct got_error *
1414create_config_files(const char *proto, const char *host, const char *port,
1415 const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1416 int mirror_references, struct got_pathlist_head *symrefs,
1417 struct got_pathlist_head *wanted_branches,
1418 struct got_pathlist_head *wanted_refs, struct got_repository *repo)
1419{
1420 const struct got_error *err = NULL((void *)0);
1421 const char *default_branch = NULL((void *)0);
1422 struct got_pathlist_entry *pe;
1423
1424 /*
1425 * If we asked for a set of wanted branches then use the first
1426 * one of those.
1427 */
1428 if (!TAILQ_EMPTY(wanted_branches)(((wanted_branches)->tqh_first) == ((void *)0))) {
1429 pe = TAILQ_FIRST(wanted_branches)((wanted_branches)->tqh_first);
1430 default_branch = pe->path;
1431 } else {
1432 /* First HEAD ref listed by server is the default branch. */
1433 TAILQ_FOREACH(pe, symrefs, entry)for((pe) = ((symrefs)->tqh_first); (pe) != ((void *)0); (pe
) = ((pe)->entry.tqe_next))
{
1434 const char *refname = pe->path;
1435 const char *target = pe->data;
1436
1437 if (strcmp(refname, GOT_REF_HEAD"HEAD") != 0)
1438 continue;
1439
1440 default_branch = target;
1441 break;
1442 }
1443 }
1444
1445 /* Create got.conf(5). */
1446 err = create_gotconfig(proto, host, port, remote_repo_path,
1447 default_branch, fetch_all_branches, wanted_branches,
1448 wanted_refs, mirror_references, repo);
1449 if (err)
1450 return err;
1451
1452 /* Create a config file Git can understand. */
1453 return create_gitconfig(git_url, default_branch, fetch_all_branches,
1454 wanted_branches, wanted_refs, mirror_references, repo);
1455}
1456
1457static const struct got_error *
1458cmd_clone(int argc, char *argv[])
1459{
1460 const struct got_error *error = NULL((void *)0);
1461 const char *uri, *dirname;
1462 char *proto, *host, *port, *repo_name, *server_path;
1463 char *default_destdir = NULL((void *)0), *id_str = NULL((void *)0);
1464 const char *repo_path;
1465 struct got_repository *repo = NULL((void *)0);
1466 struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1467 struct got_pathlist_entry *pe;
1468 struct got_object_id *pack_hash = NULL((void *)0);
1469 int ch, fetchfd = -1, fetchstatus;
1470 pid_t fetchpid = -1;
1471 struct got_fetch_progress_arg fpa;
1472 char *git_url = NULL((void *)0);
1473 int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
1474 int list_refs_only = 0;
1475
1476 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
1477 TAILQ_INIT(&symrefs)do { (&symrefs)->tqh_first = ((void *)0); (&symrefs
)->tqh_last = &(&symrefs)->tqh_first; } while (
0)
;
1478 TAILQ_INIT(&wanted_branches)do { (&wanted_branches)->tqh_first = ((void *)0); (&
wanted_branches)->tqh_last = &(&wanted_branches)->
tqh_first; } while (0)
;
1479 TAILQ_INIT(&wanted_refs)do { (&wanted_refs)->tqh_first = ((void *)0); (&wanted_refs
)->tqh_last = &(&wanted_refs)->tqh_first; } while
(0)
;
1480
1481 while ((ch = getopt(argc, argv, "ab:lmvqR:")) != -1) {
1482 switch (ch) {
1483 case 'a':
1484 fetch_all_branches = 1;
1485 break;
1486 case 'b':
1487 error = got_pathlist_append(&wanted_branches,
1488 optarg, NULL((void *)0));
1489 if (error)
1490 return error;
1491 break;
1492 case 'l':
1493 list_refs_only = 1;
1494 break;
1495 case 'm':
1496 mirror_references = 1;
1497 break;
1498 case 'v':
1499 if (verbosity < 0)
1500 verbosity = 0;
1501 else if (verbosity < 3)
1502 verbosity++;
1503 break;
1504 case 'q':
1505 verbosity = -1;
1506 break;
1507 case 'R':
1508 error = got_pathlist_append(&wanted_refs,
1509 optarg, NULL((void *)0));
1510 if (error)
1511 return error;
1512 break;
1513 default:
1514 usage_clone();
1515 break;
1516 }
1517 }
1518 argc -= optind;
1519 argv += optind;
1520
1521 if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches)(((&wanted_branches)->tqh_first) == ((void *)0)))
1522 option_conflict('a', 'b');
1523 if (list_refs_only) {
1524 if (!TAILQ_EMPTY(&wanted_branches)(((&wanted_branches)->tqh_first) == ((void *)0)))
1525 option_conflict('l', 'b');
1526 if (fetch_all_branches)
1527 option_conflict('l', 'a');
1528 if (mirror_references)
1529 option_conflict('l', 'm');
1530 if (!TAILQ_EMPTY(&wanted_refs)(((&wanted_refs)->tqh_first) == ((void *)0)))
1531 option_conflict('l', 'R');
1532 }
1533
1534 uri = argv[0];
1535
1536 if (argc == 1)
1537 dirname = NULL((void *)0);
1538 else if (argc == 2)
1539 dirname = argv[1];
1540 else
1541 usage_clone();
1542
1543 error = got_fetch_parse_uri(&proto, &host, &port, &server_path,
1544 &repo_name, uri);
1545 if (error)
1546 goto done;
1547
1548 if (asprintf(&git_url, "%s://%s%s%s%s%s", proto,
1549 host, port ? ":" : "", port ? port : "",
1550 server_path[0] != '/' ? "/" : "", server_path) == -1) {
1551 error = got_error_from_errno("asprintf");
1552 goto done;
1553 }
1554
1555 if (strcmp(proto, "git") == 0) {
1556#ifndef PROFILE
1557 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1558 "sendfd dns inet unveil", NULL((void *)0)) == -1)
1559 err(1, "pledge");
1560#endif
1561 } else if (strcmp(proto, "git+ssh") == 0 ||
1562 strcmp(proto, "ssh") == 0) {
1563#ifndef PROFILE
1564 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1565 "sendfd unveil", NULL((void *)0)) == -1)
1566 err(1, "pledge");
1567#endif
1568 } else if (strcmp(proto, "http") == 0 ||
1569 strcmp(proto, "git+http") == 0) {
1570 error = got_error_path(proto, GOT_ERR_NOT_IMPL18);
1571 goto done;
1572 } else {
1573 error = got_error_path(proto, GOT_ERR_BAD_PROTO120);
1574 goto done;
1575 }
1576 if (dirname == NULL((void *)0)) {
1577 if (asprintf(&default_destdir, "%s.git", repo_name) == -1) {
1578 error = got_error_from_errno("asprintf");
1579 goto done;
1580 }
1581 repo_path = default_destdir;
1582 } else
1583 repo_path = dirname;
1584
1585 if (!list_refs_only) {
1586 error = got_path_mkdir(repo_path);
1587 if (error &&
1588 (!(error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EISDIR21) &&
1589 !(error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EEXIST17)))
1590 goto done;
1591 if (!got_path_dir_is_empty(repo_path)) {
1592 error = got_error_path(repo_path,
1593 GOT_ERR_DIR_NOT_EMPTY75);
1594 goto done;
1595 }
1596 }
1597
1598 if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) {
1599 if (unveil(GOT_FETCH_PATH_SSH"/usr/bin/ssh", "x") != 0) {
1600 error = got_error_from_errno2("unveil",
1601 GOT_FETCH_PATH_SSH"/usr/bin/ssh");
1602 goto done;
1603 }
1604 }
1605 error = apply_unveil(repo_path, 0, NULL((void *)0));
1606 if (error)
1607 goto done;
1608
1609 if (verbosity >= 0)
1610 printf("Connecting to %s%s%s\n", host,
1611 port ? ":" : "", port ? port : "");
1612
1613 error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1614 server_path, verbosity);
1615 if (error)
1616 goto done;
1617
1618 if (!list_refs_only) {
1619 error = got_repo_init(repo_path);
1620 if (error)
1621 goto done;
1622 error = got_repo_open(&repo, repo_path, NULL((void *)0));
1623 if (error)
1624 goto done;
1625 }
1626
1627 fpa.last_scaled_size[0] = '\0';
1628 fpa.last_p_indexed = -1;
1629 fpa.last_p_resolved = -1;
1630 fpa.verbosity = verbosity;
1631 fpa.create_configs = 1;
1632 fpa.configs_created = 0;
1633 fpa.repo = repo;
1634 fpa.config_info.symrefs = &symrefs;
1635 fpa.config_info.wanted_branches = &wanted_branches;
1636 fpa.config_info.wanted_refs = &wanted_refs;
1637 fpa.config_info.proto = proto;
1638 fpa.config_info.host = host;
1639 fpa.config_info.port = port;
1640 fpa.config_info.remote_repo_path = server_path;
1641 fpa.config_info.git_url = git_url;
1642 fpa.config_info.fetch_all_branches = fetch_all_branches;
1643 fpa.config_info.mirror_references = mirror_references;
1644 error = got_fetch_pack(&pack_hash, &refs, &symrefs,
1645 GOT_FETCH_DEFAULT_REMOTE_NAME"origin", mirror_references,
1646 fetch_all_branches, &wanted_branches, &wanted_refs,
1647 list_refs_only, verbosity, fetchfd, repo,
1648 fetch_progress, &fpa);
1649 if (error)
1650 goto done;
1651
1652 if (list_refs_only) {
1653 error = list_remote_refs(&symrefs, &refs);
1654 goto done;
1655 }
1656
1657 error = got_object_id_str(&id_str, pack_hash);
1658 if (error)
1659 goto done;
1660 if (verbosity >= 0)
1661 printf("\nFetched %s.pack\n", id_str);
1662 free(id_str);
1663
1664 /* Set up references provided with the pack file. */
1665 TAILQ_FOREACH(pe, &refs, entry)for((pe) = ((&refs)->tqh_first); (pe) != ((void *)0); (
pe) = ((pe)->entry.tqe_next))
{
1666 const char *refname = pe->path;
1667 struct got_object_id *id = pe->data;
1668 char *remote_refname;
1669
1670 if (is_wanted_ref(&wanted_refs, refname) &&
1671 !mirror_references) {
1672 error = create_wanted_ref(refname, id,
1673 GOT_FETCH_DEFAULT_REMOTE_NAME"origin",
1674 verbosity - 1, repo);
1675 if (error)
1676 goto done;
1677 continue;
1678 }
1679
1680 error = create_ref(refname, id, verbosity - 1, repo);
1681 if (error)
1682 goto done;
1683
1684 if (mirror_references)
1685 continue;
1686
1687 if (strncmp("refs/heads/", refname, 11) != 0)
1688 continue;
1689
1690 if (asprintf(&remote_refname,
1691 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME"origin",
1692 refname + 11) == -1) {
1693 error = got_error_from_errno("asprintf");
1694 goto done;
1695 }
1696 error = create_ref(remote_refname, id, verbosity - 1, repo);
1697 free(remote_refname);
1698 if (error)
1699 goto done;
1700 }
1701
1702 /* Set the HEAD reference if the server provided one. */
1703 TAILQ_FOREACH(pe, &symrefs, entry)for((pe) = ((&symrefs)->tqh_first); (pe) != ((void *)0
); (pe) = ((pe)->entry.tqe_next))
{
1704 struct got_reference *target_ref;
1705 const char *refname = pe->path;
1706 const char *target = pe->data;
1707 char *remote_refname = NULL((void *)0), *remote_target = NULL((void *)0);
1708
1709 if (strcmp(refname, GOT_REF_HEAD"HEAD") != 0)
1710 continue;
1711
1712 error = got_ref_open(&target_ref, repo, target, 0);
1713 if (error) {
1714 if (error->code == GOT_ERR_NOT_REF5) {
1715 error = NULL((void *)0);
1716 continue;
1717 }
1718 goto done;
1719 }
1720
1721 error = create_symref(refname, target_ref, verbosity, repo);
1722 got_ref_close(target_ref);
1723 if (error)
1724 goto done;
1725
1726 if (mirror_references)
1727 continue;
1728
1729 if (strncmp("refs/heads/", target, 11) != 0)
1730 continue;
1731
1732 if (asprintf(&remote_refname,
1733 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME"origin",
1734 refname) == -1) {
1735 error = got_error_from_errno("asprintf");
1736 goto done;
1737 }
1738 if (asprintf(&remote_target,
1739 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME"origin",
1740 target + 11) == -1) {
1741 error = got_error_from_errno("asprintf");
1742 free(remote_refname);
1743 goto done;
1744 }
1745 error = got_ref_open(&target_ref, repo, remote_target, 0);
1746 if (error) {
1747 free(remote_refname);
1748 free(remote_target);
1749 if (error->code == GOT_ERR_NOT_REF5) {
1750 error = NULL((void *)0);
1751 continue;
1752 }
1753 goto done;
1754 }
1755 error = create_symref(remote_refname, target_ref,
1756 verbosity - 1, repo);
1757 free(remote_refname);
1758 free(remote_target);
1759 got_ref_close(target_ref);
1760 if (error)
1761 goto done;
1762 }
1763 if (pe == NULL((void *)0)) {
1764 /*
1765 * We failed to set the HEAD reference. If we asked for
1766 * a set of wanted branches use the first of one of those
1767 * which could be fetched instead.
1768 */
1769 TAILQ_FOREACH(pe, &wanted_branches, entry)for((pe) = ((&wanted_branches)->tqh_first); (pe) != ((
void *)0); (pe) = ((pe)->entry.tqe_next))
{
1770 const char *target = pe->path;
1771 struct got_reference *target_ref;
1772
1773 error = got_ref_open(&target_ref, repo, target, 0);
1774 if (error) {
1775 if (error->code == GOT_ERR_NOT_REF5) {
1776 error = NULL((void *)0);
1777 continue;
1778 }
1779 goto done;
1780 }
1781
1782 error = create_symref(GOT_REF_HEAD"HEAD", target_ref,
1783 verbosity, repo);
1784 got_ref_close(target_ref);
1785 if (error)
1786 goto done;
1787 break;
1788 }
1789 }
1790
1791 if (verbosity >= 0)
1792 printf("Created %s repository '%s'\n",
1793 mirror_references ? "mirrored" : "cloned", repo_path);
1794done:
1795 if (fetchpid > 0) {
1796 if (kill(fetchpid, SIGTERM15) == -1)
1797 error = got_error_from_errno("kill");
1798 if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL((void *)0))
1799 error = got_error_from_errno("waitpid");
1800 }
1801 if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL((void *)0))
1802 error = got_error_from_errno("close");
1803 if (repo)
1804 got_repo_close(repo);
1805 TAILQ_FOREACH(pe, &refs, entry)for((pe) = ((&refs)->tqh_first); (pe) != ((void *)0); (
pe) = ((pe)->entry.tqe_next))
{
1806 free((void *)pe->path);
1807 free(pe->data);
1808 }
1809 got_pathlist_free(&refs);
1810 TAILQ_FOREACH(pe, &symrefs, entry)for((pe) = ((&symrefs)->tqh_first); (pe) != ((void *)0
); (pe) = ((pe)->entry.tqe_next))
{
1811 free((void *)pe->path);
1812 free(pe->data);
1813 }
1814 got_pathlist_free(&symrefs);
1815 got_pathlist_free(&wanted_branches);
1816 got_pathlist_free(&wanted_refs);
1817 free(pack_hash);
1818 free(proto);
1819 free(host);
1820 free(port);
1821 free(server_path);
1822 free(repo_name);
1823 free(default_destdir);
1824 free(git_url);
1825 return error;
1826}
1827
1828static const struct got_error *
1829update_ref(struct got_reference *ref, struct got_object_id *new_id,
1830 int replace_tags, int verbosity, struct got_repository *repo)
1831{
1832 const struct got_error *err = NULL((void *)0);
1833 char *new_id_str = NULL((void *)0);
1834 struct got_object_id *old_id = NULL((void *)0);
1835
1836 err = got_object_id_str(&new_id_str, new_id);
1837 if (err)
1838 goto done;
1839
1840 if (!replace_tags &&
1841 strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) {
1842 err = got_ref_resolve(&old_id, repo, ref);
1843 if (err)
1844 goto done;
1845 if (got_object_id_cmp(old_id, new_id) == 0)
1846 goto done;
1847 if (verbosity >= 0) {
1848 printf("Rejecting update of existing tag %s: %s\n",
1849 got_ref_get_name(ref), new_id_str);
1850 }
1851 goto done;
1852 }
1853
1854 if (got_ref_is_symbolic(ref)) {
1855 if (verbosity >= 0) {
1856 printf("Replacing reference %s: %s\n",
1857 got_ref_get_name(ref),
1858 got_ref_get_symref_target(ref));
1859 }
1860 err = got_ref_change_symref_to_ref(ref, new_id);
1861 if (err)
1862 goto done;
1863 err = got_ref_write(ref, repo);
1864 if (err)
1865 goto done;
1866 } else {
1867 err = got_ref_resolve(&old_id, repo, ref);
1868 if (err)
1869 goto done;
1870 if (got_object_id_cmp(old_id, new_id) == 0)
1871 goto done;
1872
1873 err = got_ref_change_ref(ref, new_id);
1874 if (err)
1875 goto done;
1876 err = got_ref_write(ref, repo);
1877 if (err)
1878 goto done;
1879 }
1880
1881 if (verbosity >= 0)
1882 printf("Updated %s: %s\n", got_ref_get_name(ref),
1883 new_id_str);
1884done:
1885 free(old_id);
1886 free(new_id_str);
1887 return err;
1888}
1889
1890static const struct got_error *
1891update_symref(const char *refname, struct got_reference *target_ref,
1892 int verbosity, struct got_repository *repo)
1893{
1894 const struct got_error *err = NULL((void *)0), *unlock_err;
1895 struct got_reference *symref;
1896 int symref_is_locked = 0;
1897
1898 err = got_ref_open(&symref, repo, refname, 1);
1899 if (err) {
1900 if (err->code != GOT_ERR_NOT_REF5)
1901 return err;
1902 err = got_ref_alloc_symref(&symref, refname, target_ref);
1903 if (err)
1904 goto done;
1905
1906 err = got_ref_write(symref, repo);
1907 if (err)
1908 goto done;
1909
1910 if (verbosity >= 0)
1911 printf("Created reference %s: %s\n",
1912 got_ref_get_name(symref),
1913 got_ref_get_symref_target(symref));
1914 } else {
1915 symref_is_locked = 1;
1916
1917 if (strcmp(got_ref_get_symref_target(symref),
1918 got_ref_get_name(target_ref)) == 0)
1919 goto done;
1920
1921 err = got_ref_change_symref(symref,
1922 got_ref_get_name(target_ref));
1923 if (err)
1924 goto done;
1925
1926 err = got_ref_write(symref, repo);
1927 if (err)
1928 goto done;
1929
1930 if (verbosity >= 0)
1931 printf("Updated %s: %s\n", got_ref_get_name(symref),
1932 got_ref_get_symref_target(symref));
1933
1934 }
1935done:
1936 if (symref_is_locked) {
1937 unlock_err = got_ref_unlock(symref);
1938 if (unlock_err && err == NULL((void *)0))
1939 err = unlock_err;
1940 }
1941 got_ref_close(symref);
1942 return err;
1943}
1944
1945__dead__attribute__((__noreturn__)) static void
1946usage_fetch(void)
1947{
1948 fprintf(stderr(&__sF[2]), "usage: %s fetch [-a] [-b branch] [-d] [-l] "
1949 "[-r repository-path] [-t] [-q] [-v] [-R reference] "
1950 "[remote-repository-name]\n",
1951 getprogname());
1952 exit(1);
1953}
1954
1955static const struct got_error *
1956delete_missing_ref(struct got_reference *ref,
1957 int verbosity, struct got_repository *repo)
1958{
1959 const struct got_error *err = NULL((void *)0);
1960 struct got_object_id *id = NULL((void *)0);
1961 char *id_str = NULL((void *)0);
1962
1963 if (got_ref_is_symbolic(ref)) {
1964 err = got_ref_delete(ref, repo);
1965 if (err)
1966 return err;
1967 if (verbosity >= 0) {
1968 printf("Deleted reference %s: %s\n",
1969 got_ref_get_name(ref),
1970 got_ref_get_symref_target(ref));
1971 }
1972 } else {
1973 err = got_ref_resolve(&id, repo, ref);
1974 if (err)
1975 return err;
1976 err = got_object_id_str(&id_str, id);
1977 if (err)
1978 goto done;
1979
1980 err = got_ref_delete(ref, repo);
1981 if (err)
1982 goto done;
1983 if (verbosity >= 0) {
1984 printf("Deleted reference %s: %s\n",
1985 got_ref_get_name(ref), id_str);
1986 }
1987 }
1988done:
1989 free(id);
1990 free(id_str);
1991 return NULL((void *)0);
1992}
1993
1994static const struct got_error *
1995delete_missing_refs(struct got_pathlist_head *their_refs,
1996 struct got_pathlist_head *their_symrefs,
1997 const struct got_remote_repo *remote,
1998 int verbosity, struct got_repository *repo)
1999{
2000 const struct got_error *err = NULL((void *)0), *unlock_err;
2001 struct got_reflist_head my_refs;
2002 struct got_reflist_entry *re;
2003 struct got_pathlist_entry *pe;
2004 char *remote_namespace = NULL((void *)0);
2005 char *local_refname = NULL((void *)0);
2006
2007 TAILQ_INIT(&my_refs)do { (&my_refs)->tqh_first = ((void *)0); (&my_refs
)->tqh_last = &(&my_refs)->tqh_first; } while (
0)
;
2008
2009 if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name)
2010 == -1)
2011 return got_error_from_errno("asprintf");
2012
2013 err = got_ref_list(&my_refs, repo, NULL((void *)0), got_ref_cmp_by_name, NULL((void *)0));
2014 if (err)
2015 goto done;
2016
2017 TAILQ_FOREACH(re, &my_refs, entry)for((re) = ((&my_refs)->tqh_first); (re) != ((void *)0
); (re) = ((re)->entry.tqe_next))
{
2018 const char *refname = got_ref_get_name(re->ref);
2019
2020 if (!remote->mirror_references) {
2021 if (strncmp(refname, remote_namespace,
2022 strlen(remote_namespace)) == 0) {
2023 if (strcmp(refname + strlen(remote_namespace),
2024 GOT_REF_HEAD"HEAD") == 0)
2025 continue;
2026 if (asprintf(&local_refname, "refs/heads/%s",
2027 refname + strlen(remote_namespace)) == -1) {
2028 err = got_error_from_errno("asprintf");
2029 goto done;
2030 }
2031 } else if (strncmp(refname, "refs/tags/", 10) != 0)
2032 continue;
2033 }
2034
2035 TAILQ_FOREACH(pe, their_refs, entry)for((pe) = ((their_refs)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
{
2036 if (strcmp(local_refname, pe->path) == 0)
2037 break;
2038 }
2039 if (pe != NULL((void *)0))
2040 continue;
2041
2042 TAILQ_FOREACH(pe, their_symrefs, entry)for((pe) = ((their_symrefs)->tqh_first); (pe) != ((void *)
0); (pe) = ((pe)->entry.tqe_next))
{
2043 if (strcmp(local_refname, pe->path) == 0)
2044 break;
2045 }
2046 if (pe != NULL((void *)0))
2047 continue;
2048
2049 err = delete_missing_ref(re->ref, verbosity, repo);
2050 if (err)
2051 break;
2052
2053 if (local_refname) {
2054 struct got_reference *ref;
2055 err = got_ref_open(&ref, repo, local_refname, 1);
2056 if (err) {
2057 if (err->code != GOT_ERR_NOT_REF5)
2058 break;
2059 free(local_refname);
2060 local_refname = NULL((void *)0);
2061 continue;
2062 }
2063 err = delete_missing_ref(ref, verbosity, repo);
2064 if (err)
2065 break;
2066 unlock_err = got_ref_unlock(ref);
2067 got_ref_close(ref);
2068 if (unlock_err && err == NULL((void *)0)) {
2069 err = unlock_err;
2070 break;
2071 }
2072
2073 free(local_refname);
2074 local_refname = NULL((void *)0);
2075 }
2076 }
2077done:
2078 free(remote_namespace);
2079 free(local_refname);
2080 return err;
2081}
2082
2083static const struct got_error *
2084update_wanted_ref(const char *refname, struct got_object_id *id,
2085 const char *remote_repo_name, int verbosity, struct got_repository *repo)
2086{
2087 const struct got_error *err, *unlock_err;
2088 char *remote_refname;
2089 struct got_reference *ref;
2090
2091 if (strncmp("refs/", refname, 5) == 0)
2092 refname += 5;
2093
2094 if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2095 remote_repo_name, refname) == -1)
2096 return got_error_from_errno("asprintf");
2097
2098 err = got_ref_open(&ref, repo, remote_refname, 1);
2099 if (err) {
2100 if (err->code != GOT_ERR_NOT_REF5)
2101 goto done;
2102 err = create_ref(remote_refname, id, verbosity, repo);
2103 } else {
2104 err = update_ref(ref, id, 0, verbosity, repo);
2105 unlock_err = got_ref_unlock(ref);
2106 if (unlock_err && err == NULL((void *)0))
2107 err = unlock_err;
2108 got_ref_close(ref);
2109 }
2110done:
2111 free(remote_refname);
2112 return err;
2113}
2114
2115static const struct got_error *
2116cmd_fetch(int argc, char *argv[])
2117{
2118 const struct got_error *error = NULL((void *)0), *unlock_err;
2119 char *cwd = NULL((void *)0), *repo_path = NULL((void *)0);
2120 const char *remote_name;
2121 char *proto = NULL((void *)0), *host = NULL((void *)0), *port = NULL((void *)0);
2122 char *repo_name = NULL((void *)0), *server_path = NULL((void *)0);
2123 const struct got_remote_repo *remotes, *remote = NULL((void *)0);
2124 int nremotes;
2125 char *id_str = NULL((void *)0);
2126 struct got_repository *repo = NULL((void *)0);
2127 struct got_worktree *worktree = NULL((void *)0);
2128 const struct got_gotconfig *repo_conf = NULL((void *)0), *worktree_conf = NULL((void *)0);
2129 struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
2130 struct got_pathlist_entry *pe;
2131 struct got_object_id *pack_hash = NULL((void *)0);
2132 int i, ch, fetchfd = -1, fetchstatus;
2133 pid_t fetchpid = -1;
2134 struct got_fetch_progress_arg fpa;
2135 int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0;
2136 int delete_refs = 0, replace_tags = 0;
2137
2138 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
2139 TAILQ_INIT(&symrefs)do { (&symrefs)->tqh_first = ((void *)0); (&symrefs
)->tqh_last = &(&symrefs)->tqh_first; } while (
0)
;
2140 TAILQ_INIT(&wanted_branches)do { (&wanted_branches)->tqh_first = ((void *)0); (&
wanted_branches)->tqh_last = &(&wanted_branches)->
tqh_first; } while (0)
;
2141 TAILQ_INIT(&wanted_refs)do { (&wanted_refs)->tqh_first = ((void *)0); (&wanted_refs
)->tqh_last = &(&wanted_refs)->tqh_first; } while
(0)
;
2142
2143 while ((ch = getopt(argc, argv, "ab:dlr:tvqR:")) != -1) {
2144 switch (ch) {
2145 case 'a':
2146 fetch_all_branches = 1;
2147 break;
2148 case 'b':
2149 error = got_pathlist_append(&wanted_branches,
2150 optarg, NULL((void *)0));
2151 if (error)
2152 return error;
2153 break;
2154 case 'd':
2155 delete_refs = 1;
2156 break;
2157 case 'l':
2158 list_refs_only = 1;
2159 break;
2160 case 'r':
2161 repo_path = realpath(optarg, NULL((void *)0));
2162 if (repo_path == NULL((void *)0))
2163 return got_error_from_errno2("realpath",
2164 optarg);
2165 got_path_strip_trailing_slashes(repo_path);
2166 break;
2167 case 't':
2168 replace_tags = 1;
2169 break;
2170 case 'v':
2171 if (verbosity < 0)
2172 verbosity = 0;
2173 else if (verbosity < 3)
2174 verbosity++;
2175 break;
2176 case 'q':
2177 verbosity = -1;
2178 break;
2179 case 'R':
2180 error = got_pathlist_append(&wanted_refs,
2181 optarg, NULL((void *)0));
2182 if (error)
2183 return error;
2184 break;
2185 default:
2186 usage_fetch();
2187 break;
2188 }
2189 }
2190 argc -= optind;
2191 argv += optind;
2192
2193 if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches)(((&wanted_branches)->tqh_first) == ((void *)0)))
2194 option_conflict('a', 'b');
2195 if (list_refs_only) {
2196 if (!TAILQ_EMPTY(&wanted_branches)(((&wanted_branches)->tqh_first) == ((void *)0)))
2197 option_conflict('l', 'b');
2198 if (fetch_all_branches)
2199 option_conflict('l', 'a');
2200 if (delete_refs)
2201 option_conflict('l', 'd');
2202 }
2203
2204 if (argc == 0)
2205 remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME"origin";
2206 else if (argc == 1)
2207 remote_name = argv[0];
2208 else
2209 usage_fetch();
2210
2211 cwd = getcwd(NULL((void *)0), 0);
2212 if (cwd == NULL((void *)0)) {
2213 error = got_error_from_errno("getcwd");
2214 goto done;
2215 }
2216
2217 if (repo_path == NULL((void *)0)) {
2218 error = got_worktree_open(&worktree, cwd);
2219 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
2220 goto done;
2221 else
2222 error = NULL((void *)0);
2223 if (worktree) {
2224 repo_path =
2225 strdup(got_worktree_get_repo_path(worktree));
2226 if (repo_path == NULL((void *)0))
2227 error = got_error_from_errno("strdup");
2228 if (error)
2229 goto done;
2230 } else {
2231 repo_path = strdup(cwd);
2232 if (repo_path == NULL((void *)0)) {
2233 error = got_error_from_errno("strdup");
2234 goto done;
2235 }
2236 }
2237 }
2238
2239 error = got_repo_open(&repo, repo_path, NULL((void *)0));
2240 if (error)
2241 goto done;
2242
2243 if (worktree) {
2244 worktree_conf = got_worktree_get_gotconfig(worktree);
2245 if (worktree_conf) {
2246 got_gotconfig_get_remotes(&nremotes, &remotes,
2247 worktree_conf);
2248 for (i = 0; i < nremotes; i++) {
2249 if (strcmp(remotes[i].name, remote_name) == 0) {
2250 remote = &remotes[i];
2251 break;
2252 }
2253 }
2254 }
2255 }
2256 if (remote == NULL((void *)0)) {
2257 repo_conf = got_repo_get_gotconfig(repo);
2258 if (repo_conf) {
2259 got_gotconfig_get_remotes(&nremotes, &remotes,
2260 repo_conf);
2261 for (i = 0; i < nremotes; i++) {
2262 if (strcmp(remotes[i].name, remote_name) == 0) {
2263 remote = &remotes[i];
2264 break;
2265 }
2266 }
2267 }
2268 }
2269 if (remote == NULL((void *)0)) {
2270 got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
2271 for (i = 0; i < nremotes; i++) {
2272 if (strcmp(remotes[i].name, remote_name) == 0) {
2273 remote = &remotes[i];
2274 break;
2275 }
2276 }
2277 }
2278 if (remote == NULL((void *)0)) {
2279 error = got_error_path(remote_name, GOT_ERR_NO_REMOTE123);
2280 goto done;
2281 }
2282
2283 if (TAILQ_EMPTY(&wanted_branches)(((&wanted_branches)->tqh_first) == ((void *)0))) {
2284 if (!fetch_all_branches)
2285 fetch_all_branches = remote->fetch_all_branches;
2286 for (i = 0; i < remote->nbranches; i++) {
2287 got_pathlist_append(&wanted_branches,
2288 remote->branches[i], NULL((void *)0));
2289 }
2290 }
2291 if (TAILQ_EMPTY(&wanted_refs)(((&wanted_refs)->tqh_first) == ((void *)0))) {
2292 for (i = 0; i < remote->nrefs; i++) {
2293 got_pathlist_append(&wanted_refs,
2294 remote->refs[i], NULL((void *)0));
2295 }
2296 }
2297
2298 error = got_fetch_parse_uri(&proto, &host, &port, &server_path,
2299 &repo_name, remote->url);
2300 if (error)
2301 goto done;
2302
2303 if (strcmp(proto, "git") == 0) {
2304#ifndef PROFILE
2305 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2306 "sendfd dns inet unveil", NULL((void *)0)) == -1)
2307 err(1, "pledge");
2308#endif
2309 } else if (strcmp(proto, "git+ssh") == 0 ||
2310 strcmp(proto, "ssh") == 0) {
2311#ifndef PROFILE
2312 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2313 "sendfd unveil", NULL((void *)0)) == -1)
2314 err(1, "pledge");
2315#endif
2316 } else if (strcmp(proto, "http") == 0 ||
2317 strcmp(proto, "git+http") == 0) {
2318 error = got_error_path(proto, GOT_ERR_NOT_IMPL18);
2319 goto done;
2320 } else {
2321 error = got_error_path(proto, GOT_ERR_BAD_PROTO120);
2322 goto done;
2323 }
2324
2325 if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) {
2326 if (unveil(GOT_FETCH_PATH_SSH"/usr/bin/ssh", "x") != 0) {
2327 error = got_error_from_errno2("unveil",
2328 GOT_FETCH_PATH_SSH"/usr/bin/ssh");
2329 goto done;
2330 }
2331 }
2332 error = apply_unveil(got_repo_get_path(repo), 0, NULL((void *)0));
2333 if (error)
2334 goto done;
2335
2336 if (verbosity >= 0)
2337 printf("Connecting to \"%s\" %s%s%s\n", remote->name, host,
2338 port ? ":" : "", port ? port : "");
2339
2340 error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
2341 server_path, verbosity);
2342 if (error)
2343 goto done;
2344
2345 fpa.last_scaled_size[0] = '\0';
2346 fpa.last_p_indexed = -1;
2347 fpa.last_p_resolved = -1;
2348 fpa.verbosity = verbosity;
2349 fpa.repo = repo;
2350 fpa.create_configs = 0;
2351 fpa.configs_created = 0;
2352 memset(&fpa.config_info, 0, sizeof(fpa.config_info));
2353 error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
2354 remote->mirror_references, fetch_all_branches, &wanted_branches,
2355 &wanted_refs, list_refs_only, verbosity, fetchfd, repo,
2356 fetch_progress, &fpa);
2357 if (error)
2358 goto done;
2359
2360 if (list_refs_only) {
2361 error = list_remote_refs(&symrefs, &refs);
2362 goto done;
2363 }
2364
2365 if (pack_hash == NULL((void *)0)) {
2366 if (verbosity >= 0)
2367 printf("Already up-to-date\n");
2368 } else if (verbosity >= 0) {
2369 error = got_object_id_str(&id_str, pack_hash);
2370 if (error)
2371 goto done;
2372 printf("\nFetched %s.pack\n", id_str);
2373 free(id_str);
2374 id_str = NULL((void *)0);
2375 }
2376
2377 /* Update references provided with the pack file. */
2378 TAILQ_FOREACH(pe, &refs, entry)for((pe) = ((&refs)->tqh_first); (pe) != ((void *)0); (
pe) = ((pe)->entry.tqe_next))
{
2379 const char *refname = pe->path;
2380 struct got_object_id *id = pe->data;
2381 struct got_reference *ref;
2382 char *remote_refname;
2383
2384 if (is_wanted_ref(&wanted_refs, refname) &&
2385 !remote->mirror_references) {
2386 error = update_wanted_ref(refname, id,
2387 remote->name, verbosity, repo);
2388 if (error)
2389 goto done;
2390 continue;
2391 }
2392
2393 if (remote->mirror_references ||
2394 strncmp("refs/tags/", refname, 10) == 0) {
2395 error = got_ref_open(&ref, repo, refname, 1);
2396 if (error) {
2397 if (error->code != GOT_ERR_NOT_REF5)
2398 goto done;
2399 error = create_ref(refname, id, verbosity,
2400 repo);
2401 if (error)
2402 goto done;
2403 } else {
2404 error = update_ref(ref, id, replace_tags,
2405 verbosity, repo);
2406 unlock_err = got_ref_unlock(ref);
2407 if (unlock_err && error == NULL((void *)0))
2408 error = unlock_err;
2409 got_ref_close(ref);
2410 if (error)
2411 goto done;
2412 }
2413 } else if (strncmp("refs/heads/", refname, 11) == 0) {
2414 if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2415 remote_name, refname + 11) == -1) {
2416 error = got_error_from_errno("asprintf");
2417 goto done;
2418 }
2419
2420 error = got_ref_open(&ref, repo, remote_refname, 1);
2421 if (error) {
2422 if (error->code != GOT_ERR_NOT_REF5)
2423 goto done;
2424 error = create_ref(remote_refname, id,
2425 verbosity, repo);
2426 if (error)
2427 goto done;
2428 } else {
2429 error = update_ref(ref, id, replace_tags,
2430 verbosity, repo);
2431 unlock_err = got_ref_unlock(ref);
2432 if (unlock_err && error == NULL((void *)0))
2433 error = unlock_err;
2434 got_ref_close(ref);
2435 if (error)
2436 goto done;
2437 }
2438
2439 /* Also create a local branch if none exists yet. */
2440 error = got_ref_open(&ref, repo, refname, 1);
2441 if (error) {
2442 if (error->code != GOT_ERR_NOT_REF5)
2443 goto done;
2444 error = create_ref(refname, id, verbosity,
2445 repo);
2446 if (error)
2447 goto done;
2448 } else {
2449 unlock_err = got_ref_unlock(ref);
2450 if (unlock_err && error == NULL((void *)0))
2451 error = unlock_err;
2452 got_ref_close(ref);
2453 }
2454 }
2455 }
2456 if (delete_refs) {
2457 error = delete_missing_refs(&refs, &symrefs, remote,
2458 verbosity, repo);
2459 if (error)
2460 goto done;
2461 }
2462
2463 if (!remote->mirror_references) {
2464 /* Update remote HEAD reference if the server provided one. */
2465 TAILQ_FOREACH(pe, &symrefs, entry)for((pe) = ((&symrefs)->tqh_first); (pe) != ((void *)0
); (pe) = ((pe)->entry.tqe_next))
{
2466 struct got_reference *target_ref;
2467 const char *refname = pe->path;
2468 const char *target = pe->data;
2469 char *remote_refname = NULL((void *)0), *remote_target = NULL((void *)0);
2470
2471 if (strcmp(refname, GOT_REF_HEAD"HEAD") != 0)
2472 continue;
2473
2474 if (strncmp("refs/heads/", target, 11) != 0)
2475 continue;
2476
2477 if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2478 remote->name, refname) == -1) {
2479 error = got_error_from_errno("asprintf");
2480 goto done;
2481 }
2482 if (asprintf(&remote_target, "refs/remotes/%s/%s",
2483 remote->name, target + 11) == -1) {
2484 error = got_error_from_errno("asprintf");
2485 free(remote_refname);
2486 goto done;
2487 }
2488
2489 error = got_ref_open(&target_ref, repo, remote_target,
2490 0);
2491 if (error) {
2492 free(remote_refname);
2493 free(remote_target);
2494 if (error->code == GOT_ERR_NOT_REF5) {
2495 error = NULL((void *)0);
2496 continue;
2497 }
2498 goto done;
2499 }
2500 error = update_symref(remote_refname, target_ref,
2501 verbosity, repo);
2502 free(remote_refname);
2503 free(remote_target);
2504 got_ref_close(target_ref);
2505 if (error)
2506 goto done;
2507 }
2508 }
2509done:
2510 if (fetchpid > 0) {
2511 if (kill(fetchpid, SIGTERM15) == -1)
2512 error = got_error_from_errno("kill");
2513 if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL((void *)0))
2514 error = got_error_from_errno("waitpid");
2515 }
2516 if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL((void *)0))
2517 error = got_error_from_errno("close");
2518 if (repo)
2519 got_repo_close(repo);
2520 if (worktree)
2521 got_worktree_close(worktree);
2522 TAILQ_FOREACH(pe, &refs, entry)for((pe) = ((&refs)->tqh_first); (pe) != ((void *)0); (
pe) = ((pe)->entry.tqe_next))
{
2523 free((void *)pe->path);
2524 free(pe->data);
2525 }
2526 got_pathlist_free(&refs);
2527 TAILQ_FOREACH(pe, &symrefs, entry)for((pe) = ((&symrefs)->tqh_first); (pe) != ((void *)0
); (pe) = ((pe)->entry.tqe_next))
{
2528 free((void *)pe->path);
2529 free(pe->data);
2530 }
2531 got_pathlist_free(&symrefs);
2532 got_pathlist_free(&wanted_branches);
2533 got_pathlist_free(&wanted_refs);
2534 free(id_str);
2535 free(cwd);
2536 free(repo_path);
2537 free(pack_hash);
2538 free(proto);
2539 free(host);
2540 free(port);
2541 free(server_path);
2542 free(repo_name);
2543 return error;
2544}
2545
2546
2547__dead__attribute__((__noreturn__)) static void
2548usage_checkout(void)
2549{
2550 fprintf(stderr(&__sF[2]), "usage: %s checkout [-E] [-b branch] [-c commit] "
2551 "[-p prefix] repository-path [worktree-path]\n", getprogname());
2552 exit(1);
2553}
2554
2555static void
2556show_worktree_base_ref_warning(void)
2557{
2558 fprintf(stderr(&__sF[2]), "%s: warning: could not create a reference "
2559 "to the work tree's base commit; the commit could be "
2560 "garbage-collected by Git; making the repository "
2561 "writable and running 'got update' will prevent this\n",
2562 getprogname());
2563}
2564
2565struct got_checkout_progress_arg {
2566 const char *worktree_path;
2567 int had_base_commit_ref_error;
2568};
2569
2570static const struct got_error *
2571checkout_progress(void *arg, unsigned char status, const char *path)
2572{
2573 struct got_checkout_progress_arg *a = arg;
2574
2575 /* Base commit bump happens silently. */
2576 if (status == GOT_STATUS_BUMP_BASE'b')
2577 return NULL((void *)0);
2578
2579 if (status == GOT_STATUS_BASE_REF_ERR'B') {
2580 a->had_base_commit_ref_error = 1;
2581 return NULL((void *)0);
2582 }
2583
2584 while (path[0] == '/')
2585 path++;
2586
2587 printf("%c %s/%s\n", status, a->worktree_path, path);
2588 return NULL((void *)0);
2589}
2590
2591static const struct got_error *
2592check_cancelled(void *arg)
2593{
2594 if (sigint_received || sigpipe_received)
2595 return got_error(GOT_ERR_CANCELLED49);
2596 return NULL((void *)0);
2597}
2598
2599static const struct got_error *
2600check_linear_ancestry(struct got_object_id *commit_id,
2601 struct got_object_id *base_commit_id, int allow_forwards_in_time_only,
2602 struct got_repository *repo)
2603{
2604 const struct got_error *err = NULL((void *)0);
2605 struct got_object_id *yca_id;
2606
2607 err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
2608 commit_id, base_commit_id, repo, check_cancelled, NULL((void *)0));
2609 if (err)
2610 return err;
2611
2612 if (yca_id == NULL((void *)0))
2613 return got_error(GOT_ERR_ANCESTRY55);
2614
2615 /*
2616 * Require a straight line of history between the target commit
2617 * and the work tree's base commit.
2618 *
2619 * Non-linear situations such as this require a rebase:
2620 *
2621 * (commit) D F (base_commit)
2622 * \ /
2623 * C E
2624 * \ /
2625 * B (yca)
2626 * |
2627 * A
2628 *
2629 * 'got update' only handles linear cases:
2630 * Update forwards in time: A (base/yca) - B - C - D (commit)
2631 * Update backwards in time: D (base) - C - B - A (commit/yca)
2632 */
2633 if (allow_forwards_in_time_only) {
2634 if (got_object_id_cmp(base_commit_id, yca_id) != 0)
2635 return got_error(GOT_ERR_ANCESTRY55);
2636 } else if (got_object_id_cmp(commit_id, yca_id) != 0 &&
2637 got_object_id_cmp(base_commit_id, yca_id) != 0)
2638 return got_error(GOT_ERR_ANCESTRY55);
2639
2640 free(yca_id);
2641 return NULL((void *)0);
2642}
2643
2644static const struct got_error *
2645check_same_branch(struct got_object_id *commit_id,
2646 struct got_reference *head_ref, struct got_object_id *yca_id,
2647 struct got_repository *repo)
2648{
2649 const struct got_error *err = NULL((void *)0);
2650 struct got_commit_graph *graph = NULL((void *)0);
2651 struct got_object_id *head_commit_id = NULL((void *)0);
2652 int is_same_branch = 0;
2653
2654 err = got_ref_resolve(&head_commit_id, repo, head_ref);
2655 if (err)
2656 goto done;
2657
2658 if (got_object_id_cmp(head_commit_id, commit_id) == 0) {
2659 is_same_branch = 1;
2660 goto done;
2661 }
2662 if (yca_id && got_object_id_cmp(commit_id, yca_id) == 0) {
2663 is_same_branch = 1;
2664 goto done;
2665 }
2666
2667 err = got_commit_graph_open(&graph, "/", 1);
2668 if (err)
2669 goto done;
2670
2671 err = got_commit_graph_iter_start(graph, head_commit_id, repo,
2672 check_cancelled, NULL((void *)0));
2673 if (err)
2674 goto done;
2675
2676 for (;;) {
2677 struct got_object_id *id;
2678 err = got_commit_graph_iter_next(&id, graph, repo,
2679 check_cancelled, NULL((void *)0));
2680 if (err) {
2681 if (err->code == GOT_ERR_ITER_COMPLETED46)
2682 err = NULL((void *)0);
2683 break;
2684 }
2685
2686 if (id) {
2687 if (yca_id && got_object_id_cmp(id, yca_id) == 0)
2688 break;
2689 if (got_object_id_cmp(id, commit_id) == 0) {
2690 is_same_branch = 1;
2691 break;
2692 }
2693 }
2694 }
2695done:
2696 if (graph)
2697 got_commit_graph_close(graph);
2698 free(head_commit_id);
2699 if (!err && !is_same_branch)
2700 err = got_error(GOT_ERR_ANCESTRY55);
2701 return err;
2702}
2703
2704static const struct got_error *
2705checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str)
2706{
2707 static char msg[512];
2708 const char *branch_name;
2709
2710 if (got_ref_is_symbolic(ref))
2711 branch_name = got_ref_get_symref_target(ref);
2712 else
2713 branch_name = got_ref_get_name(ref);
2714
2715 if (strncmp("refs/heads/", branch_name, 11) == 0)
2716 branch_name += 11;
2717
2718 snprintf(msg, sizeof(msg),
2719 "target commit is not contained in branch '%s'; "
2720 "the branch to use must be specified with -b; "
2721 "if necessary a new branch can be created for "
2722 "this commit with 'got branch -c %s BRANCH_NAME'",
2723 branch_name, commit_id_str);
2724
2725 return got_error_msg(GOT_ERR_ANCESTRY55, msg);
2726}
2727
2728static const struct got_error *
2729cmd_checkout(int argc, char *argv[])
2730{
2731 const struct got_error *error = NULL((void *)0);
2732 struct got_repository *repo = NULL((void *)0);
2733 struct got_reference *head_ref = NULL((void *)0);
2734 struct got_worktree *worktree = NULL((void *)0);
2735 char *repo_path = NULL((void *)0);
2736 char *worktree_path = NULL((void *)0);
2737 const char *path_prefix = "";
2738 const char *branch_name = GOT_REF_HEAD"HEAD";
2739 char *commit_id_str = NULL((void *)0);
2740 char *cwd = NULL((void *)0);
2741 int ch, same_path_prefix, allow_nonempty = 0;
2742 struct got_pathlist_head paths;
2743 struct got_checkout_progress_arg cpa;
2744
2745 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
2746
2747 while ((ch = getopt(argc, argv, "b:c:Ep:")) != -1) {
2748 switch (ch) {
2749 case 'b':
2750 branch_name = optarg;
2751 break;
2752 case 'c':
2753 commit_id_str = strdup(optarg);
2754 if (commit_id_str == NULL((void *)0))
2755 return got_error_from_errno("strdup");
2756 break;
2757 case 'E':
2758 allow_nonempty = 1;
2759 break;
2760 case 'p':
2761 path_prefix = optarg;
2762 break;
2763 default:
2764 usage_checkout();
2765 /* NOTREACHED */
2766 }
2767 }
2768
2769 argc -= optind;
2770 argv += optind;
2771
2772#ifndef PROFILE
2773 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2774 "unveil", NULL((void *)0)) == -1)
2775 err(1, "pledge");
2776#endif
2777 if (argc == 1) {
2778 char *base, *dotgit;
2779 const char *path;
2780 repo_path = realpath(argv[0], NULL((void *)0));
2781 if (repo_path == NULL((void *)0))
2782 return got_error_from_errno2("realpath", argv[0]);
2783 cwd = getcwd(NULL((void *)0), 0);
2784 if (cwd == NULL((void *)0)) {
2785 error = got_error_from_errno("getcwd");
2786 goto done;
2787 }
2788 if (path_prefix[0])
2789 path = path_prefix;
2790 else
2791 path = repo_path;
2792 error = got_path_basename(&base, path);
2793 if (error)
2794 goto done;
2795 dotgit = strstr(base, ".git");
2796 if (dotgit)
2797 *dotgit = '\0';
2798 if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) {
2799 error = got_error_from_errno("asprintf");
2800 free(base);
2801 goto done;
2802 }
2803 free(base);
2804 } else if (argc == 2) {
2805 repo_path = realpath(argv[0], NULL((void *)0));
2806 if (repo_path == NULL((void *)0)) {
2807 error = got_error_from_errno2("realpath", argv[0]);
2808 goto done;
2809 }
2810 worktree_path = realpath(argv[1], NULL((void *)0));
2811 if (worktree_path == NULL((void *)0)) {
2812 if (errno(*__errno()) != ENOENT2) {
2813 error = got_error_from_errno2("realpath",
2814 argv[1]);
2815 goto done;
2816 }
2817 worktree_path = strdup(argv[1]);
2818 if (worktree_path == NULL((void *)0)) {
2819 error = got_error_from_errno("strdup");
2820 goto done;
2821 }
2822 }
2823 } else
2824 usage_checkout();
2825
2826 got_path_strip_trailing_slashes(repo_path);
2827 got_path_strip_trailing_slashes(worktree_path);
2828
2829 error = got_repo_open(&repo, repo_path, NULL((void *)0));
2830 if (error != NULL((void *)0))
2831 goto done;
2832
2833 /* Pre-create work tree path for unveil(2) */
2834 error = got_path_mkdir(worktree_path);
2835 if (error) {
2836 if (!(error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EISDIR21) &&
2837 !(error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EEXIST17))
2838 goto done;
2839 if (!allow_nonempty &&
2840 !got_path_dir_is_empty(worktree_path)) {
2841 error = got_error_path(worktree_path,
2842 GOT_ERR_DIR_NOT_EMPTY75);
2843 goto done;
2844 }
2845 }
2846
2847 error = apply_unveil(got_repo_get_path(repo), 0, worktree_path);
2848 if (error)
2849 goto done;
2850
2851 error = got_ref_open(&head_ref, repo, branch_name, 0);
2852 if (error != NULL((void *)0))
2853 goto done;
2854
2855 error = got_worktree_init(worktree_path, head_ref, path_prefix, repo);
2856 if (error != NULL((void *)0) && !(error->code == GOT_ERR_ERRNO1 && errno(*__errno()) == EEXIST17))
2857 goto done;
2858
2859 error = got_worktree_open(&worktree, worktree_path);
2860 if (error != NULL((void *)0))
2861 goto done;
2862
2863 error = got_worktree_match_path_prefix(&same_path_prefix, worktree,
2864 path_prefix);
2865 if (error != NULL((void *)0))
2866 goto done;
2867 if (!same_path_prefix) {
2868 error = got_error(GOT_ERR_PATH_PREFIX54);
2869 goto done;
2870 }
2871
2872 if (commit_id_str) {
2873 struct got_object_id *commit_id;
2874 struct got_reflist_head refs;
2875 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
2876 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name,
2877 NULL((void *)0));
2878 if (error)
2879 goto done;
2880 error = got_repo_match_object_id(&commit_id, NULL((void *)0),
2881 commit_id_str, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
2882 got_ref_list_free(&refs);
2883 if (error)
2884 goto done;
2885 error = check_linear_ancestry(commit_id,
2886 got_worktree_get_base_commit_id(worktree), 0, repo);
2887 if (error != NULL((void *)0)) {
2888 free(commit_id);
2889 if (error->code == GOT_ERR_ANCESTRY55) {
2890 error = checkout_ancestry_error(
2891 head_ref, commit_id_str);
2892 }
2893 goto done;
2894 }
2895 error = check_same_branch(commit_id, head_ref, NULL((void *)0), repo);
2896 if (error) {
2897 if (error->code == GOT_ERR_ANCESTRY55) {
2898 error = checkout_ancestry_error(
2899 head_ref, commit_id_str);
2900 }
2901 goto done;
2902 }
2903 error = got_worktree_set_base_commit_id(worktree, repo,
2904 commit_id);
2905 free(commit_id);
2906 if (error)
2907 goto done;
2908 }
2909
2910 error = got_pathlist_append(&paths, "", NULL((void *)0));
2911 if (error)
2912 goto done;
2913 cpa.worktree_path = worktree_path;
2914 cpa.had_base_commit_ref_error = 0;
2915 error = got_worktree_checkout_files(worktree, &paths, repo,
2916 checkout_progress, &cpa, check_cancelled, NULL((void *)0));
2917 if (error != NULL((void *)0))
2918 goto done;
2919
2920 printf("Now shut up and hack\n");
2921 if (cpa.had_base_commit_ref_error)
2922 show_worktree_base_ref_warning();
2923done:
2924 got_pathlist_free(&paths);
2925 free(commit_id_str);
2926 free(repo_path);
2927 free(worktree_path);
2928 free(cwd);
2929 return error;
2930}
2931
2932struct got_update_progress_arg {
2933 int did_something;
2934 int conflicts;
2935 int obstructed;
2936 int not_updated;
2937};
2938
2939void
2940print_update_progress_stats(struct got_update_progress_arg *upa)
2941{
2942 if (!upa->did_something)
2943 return;
2944
2945 if (upa->conflicts > 0)
2946 printf("Files with new merge conflicts: %d\n", upa->conflicts);
2947 if (upa->obstructed > 0)
2948 printf("File paths obstructed by a non-regular file: %d\n",
2949 upa->obstructed);
2950 if (upa->not_updated > 0)
2951 printf("Files not updated because of existing merge "
2952 "conflicts: %d\n", upa->not_updated);
2953}
2954
2955__dead__attribute__((__noreturn__)) static void
2956usage_update(void)
2957{
2958 fprintf(stderr(&__sF[2]), "usage: %s update [-b branch] [-c commit] [path ...]\n",
2959 getprogname());
2960 exit(1);
2961}
2962
2963static const struct got_error *
2964update_progress(void *arg, unsigned char status, const char *path)
2965{
2966 struct got_update_progress_arg *upa = arg;
2967
2968 if (status == GOT_STATUS_EXISTS'E' ||
2969 status == GOT_STATUS_BASE_REF_ERR'B')
2970 return NULL((void *)0);
2971
2972 upa->did_something = 1;
2973
2974 /* Base commit bump happens silently. */
2975 if (status == GOT_STATUS_BUMP_BASE'b')
2976 return NULL((void *)0);
2977
2978 if (status == GOT_STATUS_CONFLICT'C')
2979 upa->conflicts++;
2980 if (status == GOT_STATUS_OBSTRUCTED'~')
2981 upa->obstructed++;
2982 if (status == GOT_STATUS_CANNOT_UPDATE'#')
2983 upa->not_updated++;
2984
2985 while (path[0] == '/')
2986 path++;
2987 printf("%c %s\n", status, path);
2988 return NULL((void *)0);
2989}
2990
2991static const struct got_error *
2992switch_head_ref(struct got_reference *head_ref,
2993 struct got_object_id *commit_id, struct got_worktree *worktree,
2994 struct got_repository *repo)
2995{
2996 const struct got_error *err = NULL((void *)0);
2997 char *base_id_str;
2998 int ref_has_moved = 0;
2999
3000 /* Trivial case: switching between two different references. */
3001 if (strcmp(got_ref_get_name(head_ref),
3002 got_worktree_get_head_ref_name(worktree)) != 0) {
3003 printf("Switching work tree from %s to %s\n",
3004 got_worktree_get_head_ref_name(worktree),
3005 got_ref_get_name(head_ref));
3006 return got_worktree_set_head_ref(worktree, head_ref);
3007 }
3008
3009 err = check_linear_ancestry(commit_id,
3010 got_worktree_get_base_commit_id(worktree), 0, repo);
3011 if (err) {
3012 if (err->code != GOT_ERR_ANCESTRY55)
3013 return err;
3014 ref_has_moved = 1;
3015 }
3016 if (!ref_has_moved)
3017 return NULL((void *)0);
3018
3019 /* Switching to a rebased branch with the same reference name. */
3020 err = got_object_id_str(&base_id_str,
3021 got_worktree_get_base_commit_id(worktree));
3022 if (err)
3023 return err;
3024 printf("Reference %s now points at a different branch\n",
3025 got_worktree_get_head_ref_name(worktree));
3026 printf("Switching work tree from %s to %s\n", base_id_str,
3027 got_worktree_get_head_ref_name(worktree));
3028 return NULL((void *)0);
3029}
3030
3031static const struct got_error *
3032check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
3033{
3034 const struct got_error *err;
3035 int in_progress;
3036
3037 err = got_worktree_rebase_in_progress(&in_progress, worktree);
3038 if (err)
3039 return err;
3040 if (in_progress)
3041 return got_error(GOT_ERR_REBASING88);
3042
3043 err = got_worktree_histedit_in_progress(&in_progress, worktree);
3044 if (err)
3045 return err;
3046 if (in_progress)
3047 return got_error(GOT_ERR_HISTEDIT_BUSY96);
3048
3049 return NULL((void *)0);
3050}
3051
3052static const struct got_error *
3053get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc,
3054 char *argv[], struct got_worktree *worktree)
3055{
3056 const struct got_error *err = NULL((void *)0);
3057 char *path;
3058 int i;
3059
3060 if (argc == 0) {
3061 path = strdup("");
3062 if (path == NULL((void *)0))
3063 return got_error_from_errno("strdup");
3064 return got_pathlist_append(paths, path, NULL((void *)0));
3065 }
3066
3067 for (i = 0; i < argc; i++) {
3068 err = got_worktree_resolve_path(&path, worktree, argv[i]);
3069 if (err)
3070 break;
3071 err = got_pathlist_append(paths, path, NULL((void *)0));
3072 if (err) {
3073 free(path);
3074 break;
3075 }
3076 }
3077
3078 return err;
3079}
3080
3081static const struct got_error *
3082wrap_not_worktree_error(const struct got_error *orig_err,
3083 const char *cmdname, const char *path)
3084{
3085 const struct got_error *err;
3086 struct got_repository *repo;
3087 static char msg[512];
3088
3089 err = got_repo_open(&repo, path, NULL((void *)0));
3090 if (err)
3091 return orig_err;
3092
3093 snprintf(msg, sizeof(msg),
3094 "'got %s' needs a work tree in addition to a git repository\n"
3095 "Work trees can be checked out from this Git repository with "
3096 "'got checkout'.\n"
3097 "The got(1) manual page contains more information.", cmdname);
3098 err = got_error_msg(GOT_ERR_NOT_WORKTREE60, msg);
3099 got_repo_close(repo);
3100 return err;
3101}
3102
3103static const struct got_error *
3104cmd_update(int argc, char *argv[])
3105{
3106 const struct got_error *error = NULL((void *)0);
3107 struct got_repository *repo = NULL((void *)0);
3108 struct got_worktree *worktree = NULL((void *)0);
3109 char *worktree_path = NULL((void *)0);
3110 struct got_object_id *commit_id = NULL((void *)0);
3111 char *commit_id_str = NULL((void *)0);
3112 const char *branch_name = NULL((void *)0);
3113 struct got_reference *head_ref = NULL((void *)0);
3114 struct got_pathlist_head paths;
3115 struct got_pathlist_entry *pe;
3116 int ch;
3117 struct got_update_progress_arg upa;
3118
3119 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
3120
3121 while ((ch = getopt(argc, argv, "b:c:")) != -1) {
3122 switch (ch) {
3123 case 'b':
3124 branch_name = optarg;
3125 break;
3126 case 'c':
3127 commit_id_str = strdup(optarg);
3128 if (commit_id_str == NULL((void *)0))
3129 return got_error_from_errno("strdup");
3130 break;
3131 default:
3132 usage_update();
3133 /* NOTREACHED */
3134 }
3135 }
3136
3137 argc -= optind;
3138 argv += optind;
3139
3140#ifndef PROFILE
3141 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
3142 "unveil", NULL((void *)0)) == -1)
3143 err(1, "pledge");
3144#endif
3145 worktree_path = getcwd(NULL((void *)0), 0);
3146 if (worktree_path == NULL((void *)0)) {
3147 error = got_error_from_errno("getcwd");
3148 goto done;
3149 }
3150 error = got_worktree_open(&worktree, worktree_path);
3151 if (error) {
3152 if (error->code == GOT_ERR_NOT_WORKTREE60)
3153 error = wrap_not_worktree_error(error, "update",
3154 worktree_path);
3155 goto done;
3156 }
3157
3158 error = check_rebase_or_histedit_in_progress(worktree);
3159 if (error)
3160 goto done;
3161
3162 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
3163 NULL((void *)0));
3164 if (error != NULL((void *)0))
3165 goto done;
3166
3167 error = apply_unveil(got_repo_get_path(repo), 0,
3168 got_worktree_get_root_path(worktree));
3169 if (error)
3170 goto done;
3171
3172 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
3173 if (error)
3174 goto done;
3175
3176 error = got_ref_open(&head_ref, repo, branch_name ? branch_name :
3177 got_worktree_get_head_ref_name(worktree), 0);
3178 if (error != NULL((void *)0))
3179 goto done;
3180 if (commit_id_str == NULL((void *)0)) {
3181 error = got_ref_resolve(&commit_id, repo, head_ref);
3182 if (error != NULL((void *)0))
3183 goto done;
3184 error = got_object_id_str(&commit_id_str, commit_id);
3185 if (error != NULL((void *)0))
3186 goto done;
3187 } else {
3188 struct got_reflist_head refs;
3189 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
3190 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name,
3191 NULL((void *)0));
3192 if (error)
3193 goto done;
3194 error = got_repo_match_object_id(&commit_id, NULL((void *)0),
3195 commit_id_str, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
3196 got_ref_list_free(&refs);
3197 free(commit_id_str);
3198 commit_id_str = NULL((void *)0);
3199 if (error)
3200 goto done;
3201 error = got_object_id_str(&commit_id_str, commit_id);
3202 if (error)
3203 goto done;
3204 }
3205
3206 if (branch_name) {
3207 struct got_object_id *head_commit_id;
3208 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
{
3209 if (pe->path_len == 0)
3210 continue;
3211 error = got_error_msg(GOT_ERR_BAD_PATH4,
3212 "switching between branches requires that "
3213 "the entire work tree gets updated");
3214 goto done;
3215 }
3216 error = got_ref_resolve(&head_commit_id, repo, head_ref);
3217 if (error)
3218 goto done;
3219 error = check_linear_ancestry(commit_id, head_commit_id, 0,
3220 repo);
3221 free(head_commit_id);
3222 if (error != NULL((void *)0))
3223 goto done;
3224 error = check_same_branch(commit_id, head_ref, NULL((void *)0), repo);
3225 if (error)
3226 goto done;
3227 error = switch_head_ref(head_ref, commit_id, worktree, repo);
3228 if (error)
3229 goto done;
3230 } else {
3231 error = check_linear_ancestry(commit_id,
3232 got_worktree_get_base_commit_id(worktree), 0, repo);
3233 if (error != NULL((void *)0)) {
3234 if (error->code == GOT_ERR_ANCESTRY55)
3235 error = got_error(GOT_ERR_BRANCH_MOVED77);
3236 goto done;
3237 }
3238 error = check_same_branch(commit_id, head_ref, NULL((void *)0), repo);
3239 if (error)
3240 goto done;
3241 }
3242
3243 if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
3244 commit_id) != 0) {
3245 error = got_worktree_set_base_commit_id(worktree, repo,
3246 commit_id);
3247 if (error)
3248 goto done;
3249 }
3250
3251 memset(&upa, 0, sizeof(upa));
3252 error = got_worktree_checkout_files(worktree, &paths, repo,
3253 update_progress, &upa, check_cancelled, NULL((void *)0));
3254 if (error != NULL((void *)0))
3255 goto done;
3256
3257 if (upa.did_something)
3258 printf("Updated to commit %s\n", commit_id_str);
3259 else
3260 printf("Already up-to-date\n");
3261 print_update_progress_stats(&upa);
3262done:
3263 free(worktree_path);
3264 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
3265 free((char *)pe->path);
3266 got_pathlist_free(&paths);
3267 free(commit_id);
3268 free(commit_id_str);
3269 return error;
3270}
3271
3272static const struct got_error *
3273diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
3274 const char *path, int diff_context, int ignore_whitespace,
3275 int force_text_diff, struct got_repository *repo)
3276{
3277 const struct got_error *err = NULL((void *)0);
3278 struct got_blob_object *blob1 = NULL((void *)0), *blob2 = NULL((void *)0);
3279
3280 if (blob_id1) {
3281 err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192);
3282 if (err)
3283 goto done;
3284 }
3285
3286 err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192);
3287 if (err)
3288 goto done;
3289
3290 while (path[0] == '/')
3291 path++;
3292 err = got_diff_blob(NULL((void *)0), NULL((void *)0), blob1, blob2, path, path,
3293 diff_context, ignore_whitespace, force_text_diff, stdout(&__sF[1]));
3294done:
3295 if (blob1)
3296 got_object_blob_close(blob1);
3297 got_object_blob_close(blob2);
3298 return err;
3299}
3300
3301static const struct got_error *
3302diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2,
3303 const char *path, int diff_context, int ignore_whitespace,
3304 int force_text_diff, struct got_repository *repo)
3305{
3306 const struct got_error *err = NULL((void *)0);
3307 struct got_tree_object *tree1 = NULL((void *)0), *tree2 = NULL((void *)0);
3308 struct got_diff_blob_output_unidiff_arg arg;
3309
3310 if (tree_id1) {
3311 err = got_object_open_as_tree(&tree1, repo, tree_id1);
3312 if (err)
3313 goto done;
3314 }
3315
3316 err = got_object_open_as_tree(&tree2, repo, tree_id2);
3317 if (err)
3318 goto done;
3319
3320 arg.diff_context = diff_context;
3321 arg.ignore_whitespace = ignore_whitespace;
3322 arg.force_text_diff = force_text_diff;
3323 arg.outfile = stdout(&__sF[1]);
3324 arg.line_offsets = NULL((void *)0);
3325 arg.nlines = 0;
3326 while (path[0] == '/')
3327 path++;
3328 err = got_diff_tree(tree1, tree2, path, path, repo,
3329 got_diff_blob_output_unidiff, &arg, 1);
3330done:
3331 if (tree1)
3332 got_object_tree_close(tree1);
3333 if (tree2)
3334 got_object_tree_close(tree2);
3335 return err;
3336}
3337
3338static const struct got_error *
3339get_changed_paths(struct got_pathlist_head *paths,
3340 struct got_commit_object *commit, struct got_repository *repo)
3341{
3342 const struct got_error *err = NULL((void *)0);
3343 struct got_object_id *tree_id1 = NULL((void *)0), *tree_id2 = NULL((void *)0);
3344 struct got_tree_object *tree1 = NULL((void *)0), *tree2 = NULL((void *)0);
3345 struct got_object_qid *qid;
3346
3347 qid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit))((got_object_commit_get_parent_ids(commit))->sqh_first);
3348 if (qid != NULL((void *)0)) {
3349 struct got_commit_object *pcommit;
3350 err = got_object_open_as_commit(&pcommit, repo,
3351 qid->id);
3352 if (err)
3353 return err;
3354
3355 tree_id1 = got_object_commit_get_tree_id(pcommit);
3356 got_object_commit_close(pcommit);
3357
3358 }
3359
3360 if (tree_id1) {
3361 err = got_object_open_as_tree(&tree1, repo, tree_id1);
3362 if (err)
3363 goto done;
3364 }
3365
3366 tree_id2 = got_object_commit_get_tree_id(commit);
3367 err = got_object_open_as_tree(&tree2, repo, tree_id2);
3368 if (err)
3369 goto done;
3370
3371 err = got_diff_tree(tree1, tree2, "", "", repo,
3372 got_diff_tree_collect_changed_paths, paths, 0);
3373done:
3374 if (tree1)
3375 got_object_tree_close(tree1);
3376 if (tree2)
3377 got_object_tree_close(tree2);
3378 return err;
3379}
3380
3381static const struct got_error *
3382print_patch(struct got_commit_object *commit, struct got_object_id *id,
3383 const char *path, int diff_context, struct got_repository *repo)
3384{
3385 const struct got_error *err = NULL((void *)0);
3386 struct got_commit_object *pcommit = NULL((void *)0);
3387 char *id_str1 = NULL((void *)0), *id_str2 = NULL((void *)0);
3388 struct got_object_id *obj_id1 = NULL((void *)0), *obj_id2 = NULL((void *)0);
3389 struct got_object_qid *qid;
3390
3391 qid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit))((got_object_commit_get_parent_ids(commit))->sqh_first);
3392 if (qid != NULL((void *)0)) {
3393 err = got_object_open_as_commit(&pcommit, repo,
3394 qid->id);
3395 if (err)
3396 return err;
3397 }
3398
3399 if (path && path[0] != '\0') {
3400 int obj_type;
3401 err = got_object_id_by_path(&obj_id2, repo, id, path);
3402 if (err)
3403 goto done;
3404 err = got_object_id_str(&id_str2, obj_id2);
3405 if (err) {
3406 free(obj_id2);
3407 goto done;
3408 }
3409 if (pcommit) {
3410 err = got_object_id_by_path(&obj_id1, repo,
3411 qid->id, path);
3412 if (err) {
3413 if (err->code != GOT_ERR_NO_TREE_ENTRY50) {
3414 free(obj_id2);
3415 goto done;
3416 }
3417 } else {
3418 err = got_object_id_str(&id_str1, obj_id1);
3419 if (err) {
3420 free(obj_id2);
3421 goto done;
3422 }
3423 }
3424 }
3425 err = got_object_get_type(&obj_type, repo, obj_id2);
3426 if (err) {
3427 free(obj_id2);
3428 goto done;
3429 }
3430 printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3431 switch (obj_type) {
3432 case GOT_OBJ_TYPE_BLOB3:
3433 err = diff_blobs(obj_id1, obj_id2, path, diff_context,
3434 0, 0, repo);
3435 break;
3436 case GOT_OBJ_TYPE_TREE2:
3437 err = diff_trees(obj_id1, obj_id2, path, diff_context,
3438 0, 0, repo);
3439 break;
3440 default:
3441 err = got_error(GOT_ERR_OBJ_TYPE11);
3442 break;
3443 }
3444 free(obj_id1);
3445 free(obj_id2);
3446 } else {
3447 obj_id2 = got_object_commit_get_tree_id(commit);
3448 err = got_object_id_str(&id_str2, obj_id2);
3449 if (err)
3450 goto done;
3451 if (pcommit) {
3452 obj_id1 = got_object_commit_get_tree_id(pcommit);
3453 err = got_object_id_str(&id_str1, obj_id1);
3454 if (err)
3455 goto done;
3456 }
3457 printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null",
3458 id_str2);
3459 err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0,
3460 repo);
3461 }
3462done:
3463 free(id_str1);
3464 free(id_str2);
3465 if (pcommit)
3466 got_object_commit_close(pcommit);
3467 return err;
3468}
3469
3470static char *
3471get_datestr(time_t *time, char *datebuf)
3472{
3473 struct tm mytm, *tm;
3474 char *p, *s;
3475
3476 tm = gmtime_r(time, &mytm);
3477 if (tm == NULL((void *)0))
3478 return NULL((void *)0);
3479 s = asctime_r(tm, datebuf);
3480 if (s == NULL((void *)0))
3481 return NULL((void *)0);
3482 p = strchr(s, '\n');
3483 if (p)
3484 *p = '\0';
3485 return s;
3486}
3487
3488static const struct got_error *
3489match_logmsg(int *have_match, struct got_object_id *id,
3490 struct got_commit_object *commit, regex_t *regex)
3491{
3492 const struct got_error *err = NULL((void *)0);
3493 regmatch_t regmatch;
3494 char *id_str = NULL((void *)0), *logmsg = NULL((void *)0);
3495
3496 *have_match = 0;
3497
3498 err = got_object_id_str(&id_str, id);
3499 if (err)
3500 return err;
3501
3502 err = got_object_commit_get_logmsg(&logmsg, commit);
3503 if (err)
3504 goto done;
3505
3506 if (regexec(regex, logmsg, 1, &regmatch, 0) == 0)
3507 *have_match = 1;
3508done:
3509 free(id_str);
3510 free(logmsg);
3511 return err;
3512}
3513
3514static void
3515match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths,
3516 regex_t *regex)
3517{
3518 regmatch_t regmatch;
3519 struct got_pathlist_entry *pe;
3520
3521 *have_match = 0;
3522
3523 TAILQ_FOREACH(pe, changed_paths, entry)for((pe) = ((changed_paths)->tqh_first); (pe) != ((void *)
0); (pe) = ((pe)->entry.tqe_next))
{
3524 if (regexec(regex, pe->path, 1, &regmatch, 0) == 0) {
3525 *have_match = 1;
3526 break;
3527 }
3528 }
3529}
3530
3531#define GOT_COMMIT_SEP_STR"-----------------------------------------------\n" "-----------------------------------------------\n"
3532
3533static const struct got_error*
3534build_refs_str(char **refs_str, struct got_reflist_head *refs,
3535 struct got_object_id *id, struct got_repository *repo)
3536{
3537 static const struct got_error *err = NULL((void *)0);
3538 struct got_reflist_entry *re;
3539 char *s;
3540 const char *name;
3541
3542 *refs_str = NULL((void *)0);
3543
3544 TAILQ_FOREACH(re, refs, entry)for((re) = ((refs)->tqh_first); (re) != ((void *)0); (re) =
((re)->entry.tqe_next))
{
3545 struct got_tag_object *tag = NULL((void *)0);
3546 struct got_object_id *ref_id;
3547 int cmp;
3548
3549 name = got_ref_get_name(re->ref);
3550 if (strcmp(name, GOT_REF_HEAD"HEAD") == 0)
3551 continue;
3552 if (strncmp(name, "refs/", 5) == 0)
3553 name += 5;
3554 if (strncmp(name, "got/", 4) == 0)
3555 continue;
3556 if (strncmp(name, "heads/", 6) == 0)
3557 name += 6;
3558 if (strncmp(name, "remotes/", 8) == 0) {
3559 name += 8;
3560 s = strstr(name, "/" GOT_REF_HEAD"HEAD");
3561 if (s != NULL((void *)0) && s[strlen(s)] == '\0')
3562 continue;
3563 }
3564 err = got_ref_resolve(&ref_id, repo, re->ref);
3565 if (err)
3566 break;
3567 if (strncmp(name, "tags/", 5) == 0) {
3568 err = got_object_open_as_tag(&tag, repo, ref_id);
3569 if (err) {
3570 if (err->code != GOT_ERR_OBJ_TYPE11) {
3571 free(ref_id);
3572 break;
3573 }
3574 /* Ref points at something other than a tag. */
3575 err = NULL((void *)0);
3576 tag = NULL((void *)0);
3577 }
3578 }
3579 cmp = got_object_id_cmp(tag ?
3580 got_object_tag_get_object_id(tag) : ref_id, id);
3581 free(ref_id);
3582 if (tag)
3583 got_object_tag_close(tag);
3584 if (cmp != 0)
3585 continue;
3586 s = *refs_str;
3587 if (asprintf(refs_str, "%s%s%s", s ? s : "",
3588 s ? ", " : "", name) == -1) {
3589 err = got_error_from_errno("asprintf");
3590 free(s);
3591 *refs_str = NULL((void *)0);
3592 break;
3593 }
3594 free(s);
3595 }
3596
3597 return err;
3598}
3599
3600static const struct got_error *
3601print_commit(struct got_commit_object *commit, struct got_object_id *id,
3602 struct got_repository *repo, const char *path,
3603 struct got_pathlist_head *changed_paths, int show_patch,
3604 int diff_context, struct got_reflist_object_id_map *refs_idmap,
3605 const char *custom_refs_str)
3606{
3607 const struct got_error *err = NULL((void *)0);
3608 char *id_str, *datestr, *logmsg0, *logmsg, *line;
3609 char datebuf[26];
3610 time_t committer_time;
3611 const char *author, *committer;
3612 char *refs_str = NULL((void *)0);
3613
3614 err = got_object_id_str(&id_str, id);
3615 if (err)
3616 return err;
3617
3618 if (custom_refs_str == NULL((void *)0)) {
3619 struct got_reflist_head *refs;
3620 refs = got_reflist_object_id_map_lookup(refs_idmap, id);
3621 if (refs) {
3622 err = build_refs_str(&refs_str, refs, id, repo);
3623 if (err)
3624 goto done;
3625 }
3626 }
3627
3628 printf(GOT_COMMIT_SEP_STR"-----------------------------------------------\n");
3629 if (custom_refs_str)
3630 printf("commit %s (%s)\n", id_str, custom_refs_str);
3631 else
3632 printf("commit %s%s%s%s\n", id_str, refs_str ? " (" : "",
3633 refs_str ? refs_str : "", refs_str ? ")" : "");
3634 free(id_str);
3635 id_str = NULL((void *)0);
3636 free(refs_str);
3637 refs_str = NULL((void *)0);
3638 printf("from: %s\n", got_object_commit_get_author(commit));
3639 committer_time = got_object_commit_get_committer_time(commit);
3640 datestr = get_datestr(&committer_time, datebuf);
3641 if (datestr)
3642 printf("date: %s UTC\n", datestr);
3643 author = got_object_commit_get_author(commit);
3644 committer = got_object_commit_get_committer(commit);
3645 if (strcmp(author, committer) != 0)
3646 printf("via: %s\n", committer);
3647 if (got_object_commit_get_nparents(commit) > 1) {
3648 const struct got_object_id_queue *parent_ids;
3649 struct got_object_qid *qid;
3650 int n = 1;
3651 parent_ids = got_object_commit_get_parent_ids(commit);
3652 SIMPLEQ_FOREACH(qid, parent_ids, entry)for((qid) = ((parent_ids)->sqh_first); (qid) != ((void *)0
); (qid) = ((qid)->entry.sqe_next))
{
3653 err = got_object_id_str(&id_str, qid->id);
3654 if (err)
3655 goto done;
3656 printf("parent %d: %s\n", n++, id_str);
3657 free(id_str);
3658 id_str = NULL((void *)0);
3659 }
3660 }
3661
3662 err = got_object_commit_get_logmsg(&logmsg0, commit);
3663 if (err)
3664 goto done;
3665
3666 logmsg = logmsg0;
3667 do {
3668 line = strsep(&logmsg, "\n");
3669 if (line)
3670 printf(" %s\n", line);
3671 } while (line);
3672 free(logmsg0);
3673
3674 if (changed_paths) {
3675 struct got_pathlist_entry *pe;
3676 TAILQ_FOREACH(pe, changed_paths, entry)for((pe) = ((changed_paths)->tqh_first); (pe) != ((void *)
0); (pe) = ((pe)->entry.tqe_next))
{
3677 struct got_diff_changed_path *cp = pe->data;
3678 printf(" %c %s\n", cp->status, pe->path);
3679 }
3680 printf("\n");
3681 }
3682 if (show_patch) {
3683 err = print_patch(commit, id, path, diff_context, repo);
3684 if (err == 0)
3685 printf("\n");
3686 }
3687
3688 if (fflush(stdout(&__sF[1])) != 0 && err == NULL((void *)0))
3689 err = got_error_from_errno("fflush");
3690done:
3691 free(id_str);
3692 free(refs_str);
3693 return err;
3694}
3695
3696static const struct got_error *
3697print_commits(struct got_object_id *root_id, struct got_object_id *end_id,
3698 struct got_repository *repo, const char *path, int show_changed_paths,
3699 int show_patch, const char *search_pattern, int diff_context, int limit,
3700 int log_branches, int reverse_display_order,
3701 struct got_reflist_object_id_map *refs_idmap)
3702{
3703 const struct got_error *err;
3704 struct got_commit_graph *graph;
3705 regex_t regex;
3706 int have_match;
3707 struct got_object_id_queue reversed_commits;
3708 struct got_object_qid *qid;
3709 struct got_commit_object *commit;
3710 struct got_pathlist_head changed_paths;
3711 struct got_pathlist_entry *pe;
3712
3713 SIMPLEQ_INIT(&reversed_commits)do { (&reversed_commits)->sqh_first = ((void *)0); (&
reversed_commits)->sqh_last = &(&reversed_commits)
->sqh_first; } while (0)
;
3714 TAILQ_INIT(&changed_paths)do { (&changed_paths)->tqh_first = ((void *)0); (&
changed_paths)->tqh_last = &(&changed_paths)->tqh_first
; } while (0)
;
3715
3716 if (search_pattern && regcomp(&regex, search_pattern,
3717 REG_EXTENDED0001 | REG_NOSUB0004 | REG_NEWLINE0010))
3718 return got_error_msg(GOT_ERR_REGEX112, search_pattern);
3719
3720 err = got_commit_graph_open(&graph, path, !log_branches);
3721 if (err)
3722 return err;
3723 err = got_commit_graph_iter_start(graph, root_id, repo,
3724 check_cancelled, NULL((void *)0));
3725 if (err)
3726 goto done;
3727 for (;;) {
3728 struct got_object_id *id;
3729
3730 if (sigint_received || sigpipe_received)
3731 break;
3732
3733 err = got_commit_graph_iter_next(&id, graph, repo,
3734 check_cancelled, NULL((void *)0));
3735 if (err) {
3736 if (err->code == GOT_ERR_ITER_COMPLETED46)
3737 err = NULL((void *)0);
3738 break;
3739 }
3740 if (id == NULL((void *)0))
3741 break;
3742
3743 err = got_object_open_as_commit(&commit, repo, id);
3744 if (err)
3745 break;
3746
3747 if (show_changed_paths && !reverse_display_order) {
3748 err = get_changed_paths(&changed_paths, commit, repo);
3749 if (err)
3750 break;
3751 }
3752
3753 if (search_pattern) {
3754 err = match_logmsg(&have_match, id, commit, &regex);
3755 if (err) {
3756 got_object_commit_close(commit);
3757 break;
3758 }
3759 if (have_match == 0 && show_changed_paths)
3760 match_changed_paths(&have_match,
3761 &changed_paths, &regex);
3762 if (have_match == 0) {
3763 got_object_commit_close(commit);
3764 TAILQ_FOREACH(pe, &changed_paths, entry)for((pe) = ((&changed_paths)->tqh_first); (pe) != ((void
*)0); (pe) = ((pe)->entry.tqe_next))
{
3765 free((char *)pe->path);
3766 free(pe->data);
3767 }
3768 got_pathlist_free(&changed_paths);
3769 continue;
3770 }
3771 }
3772
3773 if (reverse_display_order) {
3774 err = got_object_qid_alloc(&qid, id);
3775 if (err)
3776 break;
3777 SIMPLEQ_INSERT_HEAD(&reversed_commits, qid, entry)do { if (((qid)->entry.sqe_next = (&reversed_commits)->
sqh_first) == ((void *)0)) (&reversed_commits)->sqh_last
= &(qid)->entry.sqe_next; (&reversed_commits)->
sqh_first = (qid); } while (0)
;
3778 got_object_commit_close(commit);
3779 } else {
3780 err = print_commit(commit, id, repo, path,
3781 show_changed_paths ? &changed_paths : NULL((void *)0),
3782 show_patch, diff_context, refs_idmap, NULL((void *)0));
3783 got_object_commit_close(commit);
3784 if (err)
3785 break;
3786 }
3787 if ((limit && --limit == 0) ||
3788 (end_id && got_object_id_cmp(id, end_id) == 0))
3789 break;
3790
3791 TAILQ_FOREACH(pe, &changed_paths, entry)for((pe) = ((&changed_paths)->tqh_first); (pe) != ((void
*)0); (pe) = ((pe)->entry.tqe_next))
{
3792 free((char *)pe->path);
3793 free(pe->data);
3794 }
3795 got_pathlist_free(&changed_paths);
3796 }
3797 if (reverse_display_order) {
3798 SIMPLEQ_FOREACH(qid, &reversed_commits, entry)for((qid) = ((&reversed_commits)->sqh_first); (qid) !=
((void *)0); (qid) = ((qid)->entry.sqe_next))
{
3799 err = got_object_open_as_commit(&commit, repo, qid->id);
3800 if (err)
3801 break;
3802 if (show_changed_paths) {
3803 err = get_changed_paths(&changed_paths,
3804 commit, repo);
3805 if (err)
3806 break;
3807 }
3808 err = print_commit(commit, qid->id, repo, path,
3809 show_changed_paths ? &changed_paths : NULL((void *)0),
3810 show_patch, diff_context, refs_idmap, NULL((void *)0));
3811 got_object_commit_close(commit);
3812 if (err)
3813 break;
3814 TAILQ_FOREACH(pe, &changed_paths, entry)for((pe) = ((&changed_paths)->tqh_first); (pe) != ((void
*)0); (pe) = ((pe)->entry.tqe_next))
{
3815 free((char *)pe->path);
3816 free(pe->data);
3817 }
3818 got_pathlist_free(&changed_paths);
3819 }
3820 }
3821done:
3822 while (!SIMPLEQ_EMPTY(&reversed_commits)(((&reversed_commits)->sqh_first) == ((void *)0))) {
3823 qid = SIMPLEQ_FIRST(&reversed_commits)((&reversed_commits)->sqh_first);
3824 SIMPLEQ_REMOVE_HEAD(&reversed_commits, entry)do { if (((&reversed_commits)->sqh_first = (&reversed_commits
)->sqh_first->entry.sqe_next) == ((void *)0)) (&reversed_commits
)->sqh_last = &(&reversed_commits)->sqh_first; }
while (0)
;
3825 got_object_qid_free(qid);
3826 }
3827 TAILQ_FOREACH(pe, &changed_paths, entry)for((pe) = ((&changed_paths)->tqh_first); (pe) != ((void
*)0); (pe) = ((pe)->entry.tqe_next))
{
3828 free((char *)pe->path);
3829 free(pe->data);
3830 }
3831 got_pathlist_free(&changed_paths);
3832 if (search_pattern)
3833 regfree(&regex);
3834 got_commit_graph_close(graph);
3835 return err;
3836}
3837
3838__dead__attribute__((__noreturn__)) static void
3839usage_log(void)
3840{
3841 fprintf(stderr(&__sF[2]), "usage: %s log [-b] [-c commit] [-C number] [ -l N ] "
3842 "[-p] [-P] [-x commit] [-s search-pattern] [-r repository-path] "
3843 "[-R] [path]\n", getprogname());
3844 exit(1);
3845}
3846
3847static int
3848get_default_log_limit(void)
3849{
3850 const char *got_default_log_limit;
3851 long long n;
3852 const char *errstr;
3853
3854 got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT");
3855 if (got_default_log_limit == NULL((void *)0))
3856 return 0;
3857 n = strtonum(got_default_log_limit, 0, INT_MAX2147483647, &errstr);
3858 if (errstr != NULL((void *)0))
3859 return 0;
3860 return n;
3861}
3862
3863static const struct got_error *
3864cmd_log(int argc, char *argv[])
3865{
3866 const struct got_error *error;
3867 struct got_repository *repo = NULL((void *)0);
3868 struct got_worktree *worktree = NULL((void *)0);
3869 struct got_object_id *start_id = NULL((void *)0), *end_id = NULL((void *)0);
3870 char *repo_path = NULL((void *)0), *path = NULL((void *)0), *cwd = NULL((void *)0), *in_repo_path = NULL((void *)0);
3871 const char *start_commit = NULL((void *)0), *end_commit = NULL((void *)0);
3872 const char *search_pattern = NULL((void *)0);
3873 int diff_context = -1, ch;
3874 int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0;
3875 int reverse_display_order = 0;
3876 const char *errstr;
3877 struct got_reflist_head refs;
3878 struct got_reflist_object_id_map *refs_idmap = NULL((void *)0);
3879
3880 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
3881
3882#ifndef PROFILE
3883 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
3884 NULL((void *)0))
3885 == -1)
3886 err(1, "pledge");
3887#endif
3888
3889 limit = get_default_log_limit();
3890
3891 while ((ch = getopt(argc, argv, "bpPc:C:l:r:Rs:x:")) != -1) {
3892 switch (ch) {
3893 case 'p':
3894 show_patch = 1;
3895 break;
3896 case 'P':
3897 show_changed_paths = 1;
3898 break;
3899 case 'c':
3900 start_commit = optarg;
3901 break;
3902 case 'C':
3903 diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT64,
3904 &errstr);
3905 if (errstr != NULL((void *)0))
3906 err(1, "-C option %s", errstr);
3907 break;
3908 case 'l':
3909 limit = strtonum(optarg, 0, INT_MAX2147483647, &errstr);
3910 if (errstr != NULL((void *)0))
3911 err(1, "-l option %s", errstr);
3912 break;
3913 case 'b':
3914 log_branches = 1;
3915 break;
3916 case 'r':
3917 repo_path = realpath(optarg, NULL((void *)0));
3918 if (repo_path == NULL((void *)0))
3919 return got_error_from_errno2("realpath",
3920 optarg);
3921 got_path_strip_trailing_slashes(repo_path);
3922 break;
3923 case 'R':
3924 reverse_display_order = 1;
3925 break;
3926 case 's':
3927 search_pattern = optarg;
3928 break;
3929 case 'x':
3930 end_commit = optarg;
3931 break;
3932 default:
3933 usage_log();
3934 /* NOTREACHED */
3935 }
3936 }
3937
3938 argc -= optind;
3939 argv += optind;
3940
3941 if (diff_context == -1)
3942 diff_context = 3;
3943 else if (!show_patch)
3944 errx(1, "-C requires -p");
3945
3946 cwd = getcwd(NULL((void *)0), 0);
3947 if (cwd == NULL((void *)0)) {
3948 error = got_error_from_errno("getcwd");
3949 goto done;
3950 }
3951
3952 if (repo_path == NULL((void *)0)) {
3953 error = got_worktree_open(&worktree, cwd);
3954 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
3955 goto done;
3956 error = NULL((void *)0);
3957 }
3958
3959 if (argc == 1) {
3960 if (worktree) {
3961 error = got_worktree_resolve_path(&path, worktree,
3962 argv[0]);
3963 if (error)
3964 goto done;
3965 } else {
3966 path = strdup(argv[0]);
3967 if (path == NULL((void *)0)) {
3968 error = got_error_from_errno("strdup");
3969 goto done;
3970 }
3971 }
3972 } else if (argc != 0)
3973 usage_log();
3974
3975 if (repo_path == NULL((void *)0)) {
3976 repo_path = worktree ?
3977 strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd);
3978 }
3979 if (repo_path == NULL((void *)0)) {
3980 error = got_error_from_errno("strdup");
3981 goto done;
3982 }
3983
3984 error = got_repo_open(&repo, repo_path, NULL((void *)0));
3985 if (error != NULL((void *)0))
3986 goto done;
3987
3988 error = apply_unveil(got_repo_get_path(repo), 1,
3989 worktree ? got_worktree_get_root_path(worktree) : NULL((void *)0));
3990 if (error)
3991 goto done;
3992
3993 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name, NULL((void *)0));
3994 if (error)
3995 goto done;
3996
3997 error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
3998 if (error)
3999 goto done;
4000
4001 if (start_commit == NULL((void *)0)) {
4002 struct got_reference *head_ref;
4003 struct got_commit_object *commit = NULL((void *)0);
4004 error = got_ref_open(&head_ref, repo,
4005 worktree ? got_worktree_get_head_ref_name(worktree)
4006 : GOT_REF_HEAD"HEAD", 0);
4007 if (error != NULL((void *)0))
4008 goto done;
4009 error = got_ref_resolve(&start_id, repo, head_ref);
4010 got_ref_close(head_ref);
4011 if (error != NULL((void *)0))
4012 goto done;
4013 error = got_object_open_as_commit(&commit, repo,
4014 start_id);
4015 if (error != NULL((void *)0))
4016 goto done;
4017 got_object_commit_close(commit);
4018 } else {
4019 error = got_repo_match_object_id(&start_id, NULL((void *)0),
4020 start_commit, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
4021 if (error != NULL((void *)0))
4022 goto done;
4023 }
4024 if (end_commit != NULL((void *)0)) {
4025 error = got_repo_match_object_id(&end_id, NULL((void *)0),
4026 end_commit, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
4027 if (error != NULL((void *)0))
4028 goto done;
4029 }
4030
4031 if (worktree) {
4032 /*
4033 * If a path was specified on the command line it was resolved
4034 * to a path in the work tree above. Prepend the work tree's
4035 * path prefix to obtain the corresponding in-repository path.
4036 */
4037 if (path) {
4038 const char *prefix;
4039 prefix = got_worktree_get_path_prefix(worktree);
4040 if (asprintf(&in_repo_path, "%s%s%s", prefix,
4041 (path[0] != '\0') ? "/" : "", path) == -1) {
4042 error = got_error_from_errno("asprintf");
4043 goto done;
4044 }
4045 }
4046 } else
4047 error = got_repo_map_path(&in_repo_path, repo,
4048 path ? path : "");
4049 if (error != NULL((void *)0))
4050 goto done;
4051 if (in_repo_path) {
4052 free(path);
4053 path = in_repo_path;
4054 }
4055
4056 error = print_commits(start_id, end_id, repo, path ? path : "",
4057 show_changed_paths, show_patch, search_pattern, diff_context,
4058 limit, log_branches, reverse_display_order, refs_idmap);
4059done:
4060 free(path);
4061 free(repo_path);
4062 free(cwd);
4063 if (worktree)
4064 got_worktree_close(worktree);
4065 if (repo) {
4066 const struct got_error *repo_error;
4067 repo_error = got_repo_close(repo);
4068 if (error == NULL((void *)0))
4069 error = repo_error;
4070 }
4071 if (refs_idmap)
4072 got_reflist_object_id_map_free(refs_idmap);
4073 got_ref_list_free(&refs);
4074 return error;
4075}
4076
4077__dead__attribute__((__noreturn__)) static void
4078usage_diff(void)
4079{
4080 fprintf(stderr(&__sF[2]), "usage: %s diff [-a] [-C number] [-r repository-path] "
4081 "[-s] [-w] [object1 object2 | path]\n", getprogname());
4082 exit(1);
4083}
4084
4085struct print_diff_arg {
4086 struct got_repository *repo;
4087 struct got_worktree *worktree;
4088 int diff_context;
4089 const char *id_str;
4090 int header_shown;
4091 int diff_staged;
4092 int ignore_whitespace;
4093 int force_text_diff;
4094};
4095
4096/*
4097 * Create a file which contains the target path of a symlink so we can feed
4098 * it as content to the diff engine.
4099 */
4100static const struct got_error *
4101get_symlink_target_file(int *fd, int dirfd, const char *de_name,
4102 const char *abspath)
4103{
4104 const struct got_error *err = NULL((void *)0);
4105 char target_path[PATH_MAX1024];
4106 ssize_t target_len, outlen;
4107
4108 *fd = -1;
4109
4110 if (dirfd != -1) {
4111 target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX1024);
4112 if (target_len == -1)
4113 return got_error_from_errno2("readlinkat", abspath);
4114 } else {
4115 target_len = readlink(abspath, target_path, PATH_MAX1024);
4116 if (target_len == -1)
4117 return got_error_from_errno2("readlink", abspath);
4118 }
4119
4120 *fd = got_opentempfd();
4121 if (*fd == -1)
4122 return got_error_from_errno("got_opentempfd");
4123
4124 outlen = write(*fd, target_path, target_len);
4125 if (outlen == -1) {
4126 err = got_error_from_errno("got_opentempfd");
4127 goto done;
4128 }
4129
4130 if (lseek(*fd, 0, SEEK_SET0) == -1) {
4131 err = got_error_from_errno2("lseek", abspath);
4132 goto done;
4133 }
4134done:
4135 if (err) {
4136 close(*fd);
4137 *fd = -1;
4138 }
4139 return err;
4140}
4141
4142static const struct got_error *
4143print_diff(void *arg, unsigned char status, unsigned char staged_status,
4144 const char *path, struct got_object_id *blob_id,
4145 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4146 int dirfd, const char *de_name)
4147{
4148 struct print_diff_arg *a = arg;
4149 const struct got_error *err = NULL((void *)0);
4150 struct got_blob_object *blob1 = NULL((void *)0);
4151 int fd = -1;
4152 FILE *f2 = NULL((void *)0);
4153 char *abspath = NULL((void *)0), *label1 = NULL((void *)0);
4154 struct stat sb;
4155
4156 if (a->diff_staged) {
4157 if (staged_status != GOT_STATUS_MODIFY'M' &&
4158 staged_status != GOT_STATUS_ADD'A' &&
4159 staged_status != GOT_STATUS_DELETE'D')
4160 return NULL((void *)0);
4161 } else {
4162 if (staged_status == GOT_STATUS_DELETE'D')
4163 return NULL((void *)0);
4164 if (status == GOT_STATUS_NONEXISTENT'N')
4165 return got_error_set_errno(ENOENT2, path);
4166 if (status != GOT_STATUS_MODIFY'M' &&
4167 status != GOT_STATUS_ADD'A' &&
4168 status != GOT_STATUS_DELETE'D' &&
4169 status != GOT_STATUS_CONFLICT'C')
4170 return NULL((void *)0);
4171 }
4172
4173 if (!a->header_shown) {
4174 printf("diff %s %s%s\n", a->id_str,
4175 got_worktree_get_root_path(a->worktree),
4176 a->diff_staged ? " (staged changes)" : "");
4177 a->header_shown = 1;
4178 }
4179
4180 if (a->diff_staged) {
4181 const char *label1 = NULL((void *)0), *label2 = NULL((void *)0);
4182 switch (staged_status) {
4183 case GOT_STATUS_MODIFY'M':
4184 label1 = path;
4185 label2 = path;
4186 break;
4187 case GOT_STATUS_ADD'A':
4188 label2 = path;
4189 break;
4190 case GOT_STATUS_DELETE'D':
4191 label1 = path;
4192 break;
4193 default:
4194 return got_error(GOT_ERR_FILE_STATUS68);
4195 }
4196 return got_diff_objects_as_blobs(NULL((void *)0), NULL((void *)0), blob_id,
4197 staged_blob_id, label1, label2, a->diff_context,
4198 a->ignore_whitespace, a->force_text_diff, a->repo, stdout(&__sF[1]));
4199 }
4200
4201 if (staged_status == GOT_STATUS_ADD'A' ||
4202 staged_status == GOT_STATUS_MODIFY'M') {
4203 char *id_str;
4204 err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id,
4205 8192);
4206 if (err)
4207 goto done;
4208 err = got_object_id_str(&id_str, staged_blob_id);
4209 if (err)
4210 goto done;
4211 if (asprintf(&label1, "%s (staged)", id_str) == -1) {
4212 err = got_error_from_errno("asprintf");
4213 free(id_str);
4214 goto done;
4215 }
4216 free(id_str);
4217 } else if (status != GOT_STATUS_ADD'A') {
4218 err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192);
4219 if (err)
4220 goto done;
4221 }
4222
4223 if (status != GOT_STATUS_DELETE'D') {
4224 if (asprintf(&abspath, "%s/%s",
4225 got_worktree_get_root_path(a->worktree), path) == -1) {
4226 err = got_error_from_errno("asprintf");
4227 goto done;
4228 }
4229
4230 if (dirfd != -1) {
4231 fd = openat(dirfd, de_name, O_RDONLY0x0000 | O_NOFOLLOW0x0100);
4232 if (fd == -1) {
4233 if (errno(*__errno()) != ELOOP62) {
4234 err = got_error_from_errno2("openat",
4235 abspath);
4236 goto done;
4237 }
4238 err = get_symlink_target_file(&fd, dirfd,
4239 de_name, abspath);
4240 if (err)
4241 goto done;
4242 }
4243 } else {
4244 fd = open(abspath, O_RDONLY0x0000 | O_NOFOLLOW0x0100);
4245 if (fd == -1) {
4246 if (errno(*__errno()) != ELOOP62) {
4247 err = got_error_from_errno2("open",
4248 abspath);
4249 goto done;
4250 }
4251 err = get_symlink_target_file(&fd, dirfd,
4252 de_name, abspath);
4253 if (err)
4254 goto done;
4255 }
4256 }
4257 if (fstat(fd, &sb) == -1) {
4258 err = got_error_from_errno2("fstat", abspath);
4259 goto done;
4260 }
4261 f2 = fdopen(fd, "r");
4262 if (f2 == NULL((void *)0)) {
4263 err = got_error_from_errno2("fdopen", abspath);
4264 goto done;
4265 }
4266 fd = -1;
4267 } else
4268 sb.st_size = 0;
4269
4270 err = got_diff_blob_file(blob1, label1, f2, sb.st_size, path,
4271 a->diff_context, a->ignore_whitespace, a->force_text_diff, stdout(&__sF[1]));
4272done:
4273 if (blob1)
4274 got_object_blob_close(blob1);
4275 if (f2 && fclose(f2) == EOF(-1) && err == NULL((void *)0))
4276 err = got_error_from_errno("fclose");
4277 if (fd != -1 && close(fd) == -1 && err == NULL((void *)0))
4278 err = got_error_from_errno("close");
4279 free(abspath);
4280 return err;
4281}
4282
4283static const struct got_error *
4284cmd_diff(int argc, char *argv[])
4285{
4286 const struct got_error *error;
4287 struct got_repository *repo = NULL((void *)0);
4288 struct got_worktree *worktree = NULL((void *)0);
4289 char *cwd = NULL((void *)0), *repo_path = NULL((void *)0);
4290 struct got_object_id *id1 = NULL((void *)0), *id2 = NULL((void *)0);
4291 const char *id_str1 = NULL((void *)0), *id_str2 = NULL((void *)0);
4292 char *label1 = NULL((void *)0), *label2 = NULL((void *)0);
4293 int type1, type2;
4294 int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch;
4295 int force_text_diff = 0;
4296 const char *errstr;
4297 char *path = NULL((void *)0);
4298 struct got_reflist_head refs;
4299
4300 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
4301
4302#ifndef PROFILE
4303 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4304 NULL((void *)0)) == -1)
4305 err(1, "pledge");
4306#endif
4307
4308 while ((ch = getopt(argc, argv, "aC:r:sw")) != -1) {
4309 switch (ch) {
4310 case 'a':
4311 force_text_diff = 1;
4312 break;
4313 case 'C':
4314 diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT64,
4315 &errstr);
4316 if (errstr != NULL((void *)0))
4317 err(1, "-C option %s", errstr);
4318 break;
4319 case 'r':
4320 repo_path = realpath(optarg, NULL((void *)0));
4321 if (repo_path == NULL((void *)0))
4322 return got_error_from_errno2("realpath",
4323 optarg);
4324 got_path_strip_trailing_slashes(repo_path);
4325 break;
4326 case 's':
4327 diff_staged = 1;
4328 break;
4329 case 'w':
4330 ignore_whitespace = 1;
4331 break;
4332 default:
4333 usage_diff();
4334 /* NOTREACHED */
4335 }
4336 }
4337
4338 argc -= optind;
4339 argv += optind;
4340
4341 cwd = getcwd(NULL((void *)0), 0);
4342 if (cwd == NULL((void *)0)) {
4343 error = got_error_from_errno("getcwd");
4344 goto done;
4345 }
4346 if (argc <= 1) {
4347 if (repo_path)
4348 errx(1,
4349 "-r option can't be used when diffing a work tree");
4350 error = got_worktree_open(&worktree, cwd);
4351 if (error) {
4352 if (error->code == GOT_ERR_NOT_WORKTREE60)
4353 error = wrap_not_worktree_error(error, "diff",
4354 cwd);
4355 goto done;
4356 }
4357 repo_path = strdup(got_worktree_get_repo_path(worktree));
4358 if (repo_path == NULL((void *)0)) {
4359 error = got_error_from_errno("strdup");
4360 goto done;
4361 }
4362 if (argc == 1) {
4363 error = got_worktree_resolve_path(&path, worktree,
4364 argv[0]);
4365 if (error)
4366 goto done;
4367 } else {
4368 path = strdup("");
4369 if (path == NULL((void *)0)) {
4370 error = got_error_from_errno("strdup");
4371 goto done;
4372 }
4373 }
4374 } else if (argc == 2) {
4375 if (diff_staged)
4376 errx(1, "-s option can't be used when diffing "
4377 "objects in repository");
4378 id_str1 = argv[0];
4379 id_str2 = argv[1];
4380 if (repo_path == NULL((void *)0)) {
4381 error = got_worktree_open(&worktree, cwd);
4382 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
4383 goto done;
4384 repo_path = strdup(worktree ?
4385 got_worktree_get_repo_path(worktree) : cwd);
4386 if (repo_path == NULL((void *)0)) {
4387 error = got_error_from_errno("strdup");
4388 goto done;
4389 }
4390 }
4391 } else
4392 usage_diff();
4393
4394 error = got_repo_open(&repo, repo_path, NULL((void *)0));
4395 free(repo_path);
4396 if (error != NULL((void *)0))
4397 goto done;
4398
4399 error = apply_unveil(got_repo_get_path(repo), 1,
4400 worktree ? got_worktree_get_root_path(worktree) : NULL((void *)0));
4401 if (error)
4402 goto done;
4403
4404 if (argc <= 1) {
4405 struct print_diff_arg arg;
4406 struct got_pathlist_head paths;
4407 char *id_str;
4408
4409 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
4410
4411 error = got_object_id_str(&id_str,
4412 got_worktree_get_base_commit_id(worktree));
4413 if (error)
4414 goto done;
4415 arg.repo = repo;
4416 arg.worktree = worktree;
4417 arg.diff_context = diff_context;
4418 arg.id_str = id_str;
4419 arg.header_shown = 0;
4420 arg.diff_staged = diff_staged;
4421 arg.ignore_whitespace = ignore_whitespace;
4422 arg.force_text_diff = force_text_diff;
4423
4424 error = got_pathlist_append(&paths, path, NULL((void *)0));
4425 if (error)
4426 goto done;
4427
4428 error = got_worktree_status(worktree, &paths, repo, print_diff,
4429 &arg, check_cancelled, NULL((void *)0));
4430 free(id_str);
4431 got_pathlist_free(&paths);
4432 goto done;
4433 }
4434
4435 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name, NULL((void *)0));
4436 if (error)
4437 return error;
4438
4439 error = got_repo_match_object_id(&id1, &label1, id_str1,
4440 GOT_OBJ_TYPE_ANY0, &refs, repo);
4441 if (error)
4442 goto done;
4443
4444 error = got_repo_match_object_id(&id2, &label2, id_str2,
4445 GOT_OBJ_TYPE_ANY0, &refs, repo);
4446 if (error)
4447 goto done;
4448
4449 error = got_object_get_type(&type1, repo, id1);
4450 if (error)
4451 goto done;
4452
4453 error = got_object_get_type(&type2, repo, id2);
4454 if (error)
4455 goto done;
4456
4457 if (type1 != type2) {
4458 error = got_error(GOT_ERR_OBJ_TYPE11);
4459 goto done;
4460 }
4461
4462 switch (type1) {
4463 case GOT_OBJ_TYPE_BLOB3:
4464 error = got_diff_objects_as_blobs(NULL((void *)0), NULL((void *)0), id1, id2,
4465 NULL((void *)0), NULL((void *)0), diff_context, ignore_whitespace,
4466 force_text_diff, repo, stdout(&__sF[1]));
4467 break;
4468 case GOT_OBJ_TYPE_TREE2:
4469 error = got_diff_objects_as_trees(NULL((void *)0), NULL((void *)0), id1, id2,
4470 "", "", diff_context, ignore_whitespace, force_text_diff,
4471 repo, stdout(&__sF[1]));
4472 break;
4473 case GOT_OBJ_TYPE_COMMIT1:
4474 printf("diff %s %s\n", label1, label2);
4475 error = got_diff_objects_as_commits(NULL((void *)0), NULL((void *)0), id1, id2,
4476 diff_context, ignore_whitespace, force_text_diff, repo,
4477 stdout(&__sF[1]));
4478 break;
4479 default:
4480 error = got_error(GOT_ERR_OBJ_TYPE11);
4481 }
4482done:
4483 free(label1);
4484 free(label2);
4485 free(id1);
4486 free(id2);
4487 free(path);
4488 if (worktree)
4489 got_worktree_close(worktree);
4490 if (repo) {
4491 const struct got_error *repo_error;
4492 repo_error = got_repo_close(repo);
4493 if (error == NULL((void *)0))
4494 error = repo_error;
4495 }
4496 got_ref_list_free(&refs);
4497 return error;
4498}
4499
4500__dead__attribute__((__noreturn__)) static void
4501usage_blame(void)
4502{
4503 fprintf(stderr(&__sF[2]),
4504 "usage: %s blame [-c commit] [-r repository-path] path\n",
4505 getprogname());
4506 exit(1);
4507}
4508
4509struct blame_line {
4510 int annotated;
4511 char *id_str;
4512 char *committer;
4513 char datebuf[11]; /* YYYY-MM-DD + NUL */
4514};
4515
4516struct blame_cb_args {
4517 struct blame_line *lines;
4518 int nlines;
4519 int nlines_prec;
4520 int lineno_cur;
4521 off_t *line_offsets;
4522 FILE *f;
4523 struct got_repository *repo;
4524};
4525
4526static const struct got_error *
4527blame_cb(void *arg, int nlines, int lineno, struct got_object_id *id)
4528{
4529 const struct got_error *err = NULL((void *)0);
4530 struct blame_cb_args *a = arg;
4531 struct blame_line *bline;
4532 char *line = NULL((void *)0);
4533 size_t linesize = 0;
4534 struct got_commit_object *commit = NULL((void *)0);
4535 off_t offset;
4536 struct tm tm;
4537 time_t committer_time;
4538
4539 if (nlines != a->nlines ||
4540 (lineno != -1 && lineno < 1) || lineno > a->nlines)
4541 return got_error(GOT_ERR_RANGE47);
4542
4543 if (sigint_received)
4544 return got_error(GOT_ERR_ITER_COMPLETED46);
4545
4546 if (lineno == -1)
4547 return NULL((void *)0); /* no change in this commit */
4548
4549 /* Annotate this line. */
4550 bline = &a->lines[lineno - 1];
4551 if (bline->annotated)
4552 return NULL((void *)0);
4553 err = got_object_id_str(&bline->id_str, id);
4554 if (err)
4555 return err;
4556
4557 err = got_object_open_as_commit(&commit, a->repo, id);
4558 if (err)
4559 goto done;
4560
4561 bline->committer = strdup(got_object_commit_get_committer(commit));
4562 if (bline->committer == NULL((void *)0)) {
4563 err = got_error_from_errno("strdup");
4564 goto done;
4565 }
4566
4567 committer_time = got_object_commit_get_committer_time(commit);
4568 if (localtime_r(&committer_time, &tm) == NULL((void *)0))
4569 return got_error_from_errno("localtime_r");
4570 if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
4571 &tm) == 0) {
4572 err = got_error(GOT_ERR_NO_SPACE9);
4573 goto done;
4574 }
4575 bline->annotated = 1;
4576
4577 /* Print lines annotated so far. */
4578 bline = &a->lines[a->lineno_cur - 1];
4579 if (!bline->annotated)
4580 goto done;
4581
4582 offset = a->line_offsets[a->lineno_cur - 1];
4583 if (fseeko(a->f, offset, SEEK_SET0) == -1) {
4584 err = got_error_from_errno("fseeko");
4585 goto done;
4586 }
4587
4588 while (bline->annotated) {
4589 char *smallerthan, *at, *nl, *committer;
4590 size_t len;
4591
4592 if (getline(&line, &linesize, a->f) == -1) {
4593 if (ferror(a->f)(!__isthreaded ? (((a->f)->_flags & 0x0040) != 0) :
(ferror)(a->f))
)
4594 err = got_error_from_errno("getline");
4595 break;
4596 }
4597
4598 committer = bline->committer;
4599 smallerthan = strchr(committer, '<');
4600 if (smallerthan && smallerthan[1] != '\0')
4601 committer = smallerthan + 1;
4602 at = strchr(committer, '@');
4603 if (at)
4604 *at = '\0';
4605 len = strlen(committer);
4606 if (len >= 9)
4607 committer[8] = '\0';
4608
4609 nl = strchr(line, '\n');
4610 if (nl)
4611 *nl = '\0';
4612 printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur,
4613 bline->id_str, bline->datebuf, committer, line);
4614
4615 a->lineno_cur++;
4616 bline = &a->lines[a->lineno_cur - 1];
4617 }
4618done:
4619 if (commit)
4620 got_object_commit_close(commit);
4621 free(line);
4622 return err;
4623}
4624
4625static const struct got_error *
4626cmd_blame(int argc, char *argv[])
4627{
4628 const struct got_error *error;
4629 struct got_repository *repo = NULL((void *)0);
4630 struct got_worktree *worktree = NULL((void *)0);
4631 char *path, *cwd = NULL((void *)0), *repo_path = NULL((void *)0), *in_repo_path = NULL((void *)0);
4632 char *link_target = NULL((void *)0);
4633 struct got_object_id *obj_id = NULL((void *)0);
4634 struct got_object_id *commit_id = NULL((void *)0);
4635 struct got_blob_object *blob = NULL((void *)0);
4636 char *commit_id_str = NULL((void *)0);
4637 struct blame_cb_args bca;
4638 int ch, obj_type, i;
4639 off_t filesize;
4640
4641 memset(&bca, 0, sizeof(bca));
4642
4643#ifndef PROFILE
4644 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4645 NULL((void *)0)) == -1)
4646 err(1, "pledge");
4647#endif
4648
4649 while ((ch = getopt(argc, argv, "c:r:")) != -1) {
4650 switch (ch) {
4651 case 'c':
4652 commit_id_str = optarg;
4653 break;
4654 case 'r':
4655 repo_path = realpath(optarg, NULL((void *)0));
4656 if (repo_path == NULL((void *)0))
4657 return got_error_from_errno2("realpath",
4658 optarg);
4659 got_path_strip_trailing_slashes(repo_path);
4660 break;
4661 default:
4662 usage_blame();
4663 /* NOTREACHED */
4664 }
4665 }
4666
4667 argc -= optind;
4668 argv += optind;
4669
4670 if (argc == 1)
4671 path = argv[0];
4672 else
4673 usage_blame();
4674
4675 cwd = getcwd(NULL((void *)0), 0);
4676 if (cwd == NULL((void *)0)) {
4677 error = got_error_from_errno("getcwd");
4678 goto done;
4679 }
4680 if (repo_path == NULL((void *)0)) {
4681 error = got_worktree_open(&worktree, cwd);
4682 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
4683 goto done;
4684 else
4685 error = NULL((void *)0);
4686 if (worktree) {
4687 repo_path =
4688 strdup(got_worktree_get_repo_path(worktree));
4689 if (repo_path == NULL((void *)0)) {
4690 error = got_error_from_errno("strdup");
4691 if (error)
4692 goto done;
4693 }
4694 } else {
4695 repo_path = strdup(cwd);
4696 if (repo_path == NULL((void *)0)) {
4697 error = got_error_from_errno("strdup");
4698 goto done;
4699 }
4700 }
4701 }
4702
4703 error = got_repo_open(&repo, repo_path, NULL((void *)0));
4704 if (error != NULL((void *)0))
4705 goto done;
4706
4707 if (worktree) {
4708 const char *prefix = got_worktree_get_path_prefix(worktree);
4709 char *p;
4710
4711 error = got_worktree_resolve_path(&p, worktree, path);
4712 if (error)
4713 goto done;
4714 if (asprintf(&in_repo_path, "%s%s%s", prefix,
4715 (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
4716 p) == -1) {
4717 error = got_error_from_errno("asprintf");
4718 free(p);
4719 goto done;
4720 }
4721 free(p);
4722 error = apply_unveil(got_repo_get_path(repo), 1, NULL((void *)0));
4723 } else {
4724 error = apply_unveil(got_repo_get_path(repo), 1, NULL((void *)0));
4725 if (error)
4726 goto done;
4727 error = got_repo_map_path(&in_repo_path, repo, path);
4728 }
4729 if (error)
4730 goto done;
4731
4732 if (commit_id_str == NULL((void *)0)) {
4733 struct got_reference *head_ref;
4734 error = got_ref_open(&head_ref, repo, worktree ?
4735 got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD"HEAD", 0);
4736 if (error != NULL((void *)0))
4737 goto done;
4738 error = got_ref_resolve(&commit_id, repo, head_ref);
4739 got_ref_close(head_ref);
4740 if (error != NULL((void *)0))
4741 goto done;
4742 } else {
4743 struct got_reflist_head refs;
4744 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
4745 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name,
4746 NULL((void *)0));
4747 if (error)
4748 goto done;
4749 error = got_repo_match_object_id(&commit_id, NULL((void *)0),
4750 commit_id_str, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
4751 got_ref_list_free(&refs);
4752 if (error)
4753 goto done;
4754 }
4755
4756 error = got_object_resolve_symlinks(&link_target, in_repo_path,
4757 commit_id, repo);
4758 if (error)
4759 goto done;
4760
4761 error = got_object_id_by_path(&obj_id, repo, commit_id,
4762 link_target ? link_target : in_repo_path);
4763 if (error)
4764 goto done;
4765
4766 error = got_object_get_type(&obj_type, repo, obj_id);
4767 if (error)
4768 goto done;
4769
4770 if (obj_type != GOT_OBJ_TYPE_BLOB3) {
4771 error = got_error_path(link_target ? link_target : in_repo_path,
4772 GOT_ERR_OBJ_TYPE11);
4773 goto done;
4774 }
4775
4776 error = got_object_open_as_blob(&blob, repo, obj_id, 8192);
4777 if (error)
4778 goto done;
4779 bca.f = got_opentemp();
4780 if (bca.f == NULL((void *)0)) {
4781 error = got_error_from_errno("got_opentemp");
4782 goto done;
4783 }
4784 error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
4785 &bca.line_offsets, bca.f, blob);
4786 if (error || bca.nlines == 0)
4787 goto done;
4788
4789 /* Don't include \n at EOF in the blame line count. */
4790 if (bca.line_offsets[bca.nlines - 1] == filesize)
4791 bca.nlines--;
4792
4793 bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
4794 if (bca.lines == NULL((void *)0)) {
4795 error = got_error_from_errno("calloc");
4796 goto done;
4797 }
4798 bca.lineno_cur = 1;
4799 bca.nlines_prec = 0;
4800 i = bca.nlines;
4801 while (i > 0) {
4802 i /= 10;
4803 bca.nlines_prec++;
4804 }
4805 bca.repo = repo;
4806
4807 error = got_blame(link_target ? link_target : in_repo_path, commit_id,
4808 repo, blame_cb, &bca, check_cancelled, NULL((void *)0));
4809done:
4810 free(in_repo_path);
4811 free(link_target);
4812 free(repo_path);
4813 free(cwd);
4814 free(commit_id);
4815 free(obj_id);
4816 if (blob)
4817 got_object_blob_close(blob);
4818 if (worktree)
4819 got_worktree_close(worktree);
4820 if (repo) {
4821 const struct got_error *repo_error;
4822 repo_error = got_repo_close(repo);
4823 if (error == NULL((void *)0))
4824 error = repo_error;
4825 }
4826 if (bca.lines) {
4827 for (i = 0; i < bca.nlines; i++) {
4828 struct blame_line *bline = &bca.lines[i];
4829 free(bline->id_str);
4830 free(bline->committer);
4831 }
4832 free(bca.lines);
4833 }
4834 free(bca.line_offsets);
4835 if (bca.f && fclose(bca.f) == EOF(-1) && error == NULL((void *)0))
4836 error = got_error_from_errno("fclose");
4837 return error;
4838}
4839
4840__dead__attribute__((__noreturn__)) static void
4841usage_tree(void)
4842{
4843 fprintf(stderr(&__sF[2]),
4844 "usage: %s tree [-c commit] [-r repository-path] [-iR] [path]\n",
4845 getprogname());
4846 exit(1);
4847}
4848
4849static const struct got_error *
4850print_entry(struct got_tree_entry *te, const char *id, const char *path,
4851 const char *root_path, struct got_repository *repo)
4852{
4853 const struct got_error *err = NULL((void *)0);
4854 int is_root_path = (strcmp(path, root_path) == 0);
4855 const char *modestr = "";
4856 mode_t mode = got_tree_entry_get_mode(te);
4857 char *link_target = NULL((void *)0);
4858
4859 path += strlen(root_path);
4860 while (path[0] == '/')
4861 path++;
4862
4863 if (got_object_tree_entry_is_submodule(te))
4864 modestr = "$";
4865 else if (S_ISLNK(mode)((mode & 0170000) == 0120000)) {
4866 int i;
4867
4868 err = got_tree_entry_get_symlink_target(&link_target, te, repo);
4869 if (err)
4870 return err;
4871 for (i = 0; i < strlen(link_target); i++) {
4872 if (!isprint((unsigned char)link_target[i]))
4873 link_target[i] = '?';
4874 }
4875
4876 modestr = "@";
4877 }
4878 else if (S_ISDIR(mode)((mode & 0170000) == 0040000))
4879 modestr = "/";
4880 else if (mode & S_IXUSR0000100)
4881 modestr = "*";
4882
4883 printf("%s%s%s%s%s%s%s\n", id ? id : "", path,
4884 is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr,
4885 link_target ? " -> ": "", link_target ? link_target : "");
4886
4887 free(link_target);
4888 return NULL((void *)0);
4889}
4890
4891static const struct got_error *
4892print_tree(const char *path, struct got_object_id *commit_id,
4893 int show_ids, int recurse, const char *root_path,
4894 struct got_repository *repo)
4895{
4896 const struct got_error *err = NULL((void *)0);
4897 struct got_object_id *tree_id = NULL((void *)0);
4898 struct got_tree_object *tree = NULL((void *)0);
4899 int nentries, i;
4900
4901 err = got_object_id_by_path(&tree_id, repo, commit_id, path);
4902 if (err)
4903 goto done;
4904
4905 err = got_object_open_as_tree(&tree, repo, tree_id);
4906 if (err)
4907 goto done;
4908 nentries = got_object_tree_get_nentries(tree);
4909 for (i = 0; i < nentries; i++) {
4910 struct got_tree_entry *te;
4911 char *id = NULL((void *)0);
4912
4913 if (sigint_received || sigpipe_received)
4914 break;
4915
4916 te = got_object_tree_get_entry(tree, i);
4917 if (show_ids) {
4918 char *id_str;
4919 err = got_object_id_str(&id_str,
4920 got_tree_entry_get_id(te));
4921 if (err)
4922 goto done;
4923 if (asprintf(&id, "%s ", id_str) == -1) {
4924 err = got_error_from_errno("asprintf");
4925 free(id_str);
4926 goto done;
4927 }
4928 free(id_str);
4929 }
4930 err = print_entry(te, id, path, root_path, repo);
4931 free(id);
4932 if (err)
4933 goto done;
4934
4935 if (recurse && S_ISDIR(got_tree_entry_get_mode(te))((got_tree_entry_get_mode(te) & 0170000) == 0040000)) {
4936 char *child_path;
4937 if (asprintf(&child_path, "%s%s%s", path,
4938 path[0] == '/' && path[1] == '\0' ? "" : "/",
4939 got_tree_entry_get_name(te)) == -1) {
4940 err = got_error_from_errno("asprintf");
4941 goto done;
4942 }
4943 err = print_tree(child_path, commit_id, show_ids, 1,
4944 root_path, repo);
4945 free(child_path);
4946 if (err)
4947 goto done;
4948 }
4949 }
4950done:
4951 if (tree)
4952 got_object_tree_close(tree);
4953 free(tree_id);
4954 return err;
4955}
4956
4957static const struct got_error *
4958cmd_tree(int argc, char *argv[])
4959{
4960 const struct got_error *error;
4961 struct got_repository *repo = NULL((void *)0);
4962 struct got_worktree *worktree = NULL((void *)0);
4963 const char *path, *refname = NULL((void *)0);
4964 char *cwd = NULL((void *)0), *repo_path = NULL((void *)0), *in_repo_path = NULL((void *)0);
4965 struct got_object_id *commit_id = NULL((void *)0);
4966 char *commit_id_str = NULL((void *)0);
4967 int show_ids = 0, recurse = 0;
4968 int ch;
4969
4970#ifndef PROFILE
4971 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4972 NULL((void *)0)) == -1)
4973 err(1, "pledge");
4974#endif
4975
4976 while ((ch = getopt(argc, argv, "c:r:iR")) != -1) {
4977 switch (ch) {
4978 case 'c':
4979 commit_id_str = optarg;
4980 break;
4981 case 'r':
4982 repo_path = realpath(optarg, NULL((void *)0));
4983 if (repo_path == NULL((void *)0))
4984 return got_error_from_errno2("realpath",
4985 optarg);
4986 got_path_strip_trailing_slashes(repo_path);
4987 break;
4988 case 'i':
4989 show_ids = 1;
4990 break;
4991 case 'R':
4992 recurse = 1;
4993 break;
4994 default:
4995 usage_tree();
4996 /* NOTREACHED */
4997 }
4998 }
4999
5000 argc -= optind;
5001 argv += optind;
5002
5003 if (argc == 1)
5004 path = argv[0];
5005 else if (argc > 1)
5006 usage_tree();
5007 else
5008 path = NULL((void *)0);
5009
5010 cwd = getcwd(NULL((void *)0), 0);
5011 if (cwd == NULL((void *)0)) {
5012 error = got_error_from_errno("getcwd");
5013 goto done;
5014 }
5015 if (repo_path == NULL((void *)0)) {
5016 error = got_worktree_open(&worktree, cwd);
5017 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
5018 goto done;
5019 else
5020 error = NULL((void *)0);
5021 if (worktree) {
5022 repo_path =
5023 strdup(got_worktree_get_repo_path(worktree));
5024 if (repo_path == NULL((void *)0))
5025 error = got_error_from_errno("strdup");
5026 if (error)
5027 goto done;
5028 } else {
5029 repo_path = strdup(cwd);
5030 if (repo_path == NULL((void *)0)) {
5031 error = got_error_from_errno("strdup");
5032 goto done;
5033 }
5034 }
5035 }
5036
5037 error = got_repo_open(&repo, repo_path, NULL((void *)0));
5038 if (error != NULL((void *)0))
5039 goto done;
5040
5041 if (worktree) {
5042 const char *prefix = got_worktree_get_path_prefix(worktree);
5043 char *p;
5044
5045 if (path == NULL((void *)0))
5046 path = "";
5047 error = got_worktree_resolve_path(&p, worktree, path);
5048 if (error)
5049 goto done;
5050 if (asprintf(&in_repo_path, "%s%s%s", prefix,
5051 (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5052 p) == -1) {
5053 error = got_error_from_errno("asprintf");
5054 free(p);
5055 goto done;
5056 }
5057 free(p);
5058 error = apply_unveil(got_repo_get_path(repo), 1, NULL((void *)0));
5059 if (error)
5060 goto done;
5061 } else {
5062 error = apply_unveil(got_repo_get_path(repo), 1, NULL((void *)0));
5063 if (error)
5064 goto done;
5065 if (path == NULL((void *)0))
5066 path = "/";
5067 error = got_repo_map_path(&in_repo_path, repo, path);
5068 if (error != NULL((void *)0))
5069 goto done;
5070 }
5071
5072 if (commit_id_str == NULL((void *)0)) {
5073 struct got_reference *head_ref;
5074 if (worktree)
5075 refname = got_worktree_get_head_ref_name(worktree);
5076 else
5077 refname = GOT_REF_HEAD"HEAD";
5078 error = got_ref_open(&head_ref, repo, refname, 0);
5079 if (error != NULL((void *)0))
5080 goto done;
5081 error = got_ref_resolve(&commit_id, repo, head_ref);
5082 got_ref_close(head_ref);
5083 if (error != NULL((void *)0))
5084 goto done;
5085 } else {
5086 struct got_reflist_head refs;
5087 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
5088 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name,
5089 NULL((void *)0));
5090 if (error)
5091 goto done;
5092 error = got_repo_match_object_id(&commit_id, NULL((void *)0),
5093 commit_id_str, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
5094 got_ref_list_free(&refs);
5095 if (error)
5096 goto done;
5097 }
5098
5099 error = print_tree(in_repo_path, commit_id, show_ids, recurse,
5100 in_repo_path, repo);
5101done:
5102 free(in_repo_path);
5103 free(repo_path);
5104 free(cwd);
5105 free(commit_id);
5106 if (worktree)
5107 got_worktree_close(worktree);
5108 if (repo) {
5109 const struct got_error *repo_error;
5110 repo_error = got_repo_close(repo);
5111 if (error == NULL((void *)0))
5112 error = repo_error;
5113 }
5114 return error;
5115}
5116
5117__dead__attribute__((__noreturn__)) static void
5118usage_status(void)
5119{
5120 fprintf(stderr(&__sF[2]), "usage: %s status [-s status-codes ] [path ...]\n",
5121 getprogname());
5122 exit(1);
5123}
5124
5125static const struct got_error *
5126print_status(void *arg, unsigned char status, unsigned char staged_status,
5127 const char *path, struct got_object_id *blob_id,
5128 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
5129 int dirfd, const char *de_name)
5130{
5131 if (status == staged_status && (status == GOT_STATUS_DELETE'D'))
5132 status = GOT_STATUS_NO_CHANGE' ';
5133 if (arg) {
5134 char *status_codes = arg;
5135 size_t ncodes = strlen(status_codes);
5136 int i;
5137 for (i = 0; i < ncodes ; i++) {
5138 if (status == status_codes[i] ||
5139 staged_status == status_codes[i])
5140 break;
5141 }
5142 if (i == ncodes)
5143 return NULL((void *)0);
5144 }
5145 printf("%c%c %s\n", status, staged_status, path);
5146 return NULL((void *)0);
5147}
5148
5149static const struct got_error *
5150cmd_status(int argc, char *argv[])
5151{
5152 const struct got_error *error = NULL((void *)0);
5153 struct got_repository *repo = NULL((void *)0);
5154 struct got_worktree *worktree = NULL((void *)0);
5155 char *cwd = NULL((void *)0), *status_codes = NULL((void *)0);;
5156 struct got_pathlist_head paths;
5157 struct got_pathlist_entry *pe;
5158 int ch, i;
5159
5160 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
5161
5162 while ((ch = getopt(argc, argv, "s:")) != -1) {
5163 switch (ch) {
5164 case 's':
5165 for (i = 0; i < strlen(optarg); i++) {
5166 switch (optarg[i]) {
5167 case GOT_STATUS_MODIFY'M':
5168 case GOT_STATUS_ADD'A':
5169 case GOT_STATUS_DELETE'D':
5170 case GOT_STATUS_CONFLICT'C':
5171 case GOT_STATUS_MISSING'!':
5172 case GOT_STATUS_OBSTRUCTED'~':
5173 case GOT_STATUS_UNVERSIONED'?':
5174 case GOT_STATUS_MODE_CHANGE'm':
5175 case GOT_STATUS_NONEXISTENT'N':
5176 break;
5177 default:
5178 errx(1, "invalid status code '%c'",
5179 optarg[i]);
5180 }
5181 }
5182 status_codes = optarg;
5183 break;
5184 default:
5185 usage_status();
5186 /* NOTREACHED */
5187 }
5188 }
5189
5190 argc -= optind;
5191 argv += optind;
5192
5193#ifndef PROFILE
5194 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5195 NULL((void *)0)) == -1)
5196 err(1, "pledge");
5197#endif
5198 cwd = getcwd(NULL((void *)0), 0);
5199 if (cwd == NULL((void *)0)) {
5200 error = got_error_from_errno("getcwd");
5201 goto done;
5202 }
5203
5204 error = got_worktree_open(&worktree, cwd);
5205 if (error) {
5206 if (error->code == GOT_ERR_NOT_WORKTREE60)
5207 error = wrap_not_worktree_error(error, "status", cwd);
5208 goto done;
5209 }
5210
5211 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
5212 NULL((void *)0));
5213 if (error != NULL((void *)0))
5214 goto done;
5215
5216 error = apply_unveil(got_repo_get_path(repo), 1,
5217 got_worktree_get_root_path(worktree));
5218 if (error)
5219 goto done;
5220
5221 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
5222 if (error)
5223 goto done;
5224
5225 error = got_worktree_status(worktree, &paths, repo, print_status,
5226 status_codes, check_cancelled, NULL((void *)0));
5227done:
5228 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
5229 free((char *)pe->path);
5230 got_pathlist_free(&paths);
5231 free(cwd);
5232 return error;
5233}
5234
5235__dead__attribute__((__noreturn__)) static void
5236usage_ref(void)
5237{
5238 fprintf(stderr(&__sF[2]),
5239 "usage: %s ref [-r repository] [-l] [-c object] [-s reference] "
5240 "[-d] [name]\n",
5241 getprogname());
5242 exit(1);
5243}
5244
5245static const struct got_error *
5246list_refs(struct got_repository *repo, const char *refname)
5247{
5248 static const struct got_error *err = NULL((void *)0);
5249 struct got_reflist_head refs;
5250 struct got_reflist_entry *re;
5251
5252 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
5253 err = got_ref_list(&refs, repo, refname, got_ref_cmp_by_name, NULL((void *)0));
5254 if (err)
5255 return err;
5256
5257 TAILQ_FOREACH(re, &refs, entry)for((re) = ((&refs)->tqh_first); (re) != ((void *)0); (
re) = ((re)->entry.tqe_next))
{
5258 char *refstr;
5259 refstr = got_ref_to_str(re->ref);
5260 if (refstr == NULL((void *)0))
5261 return got_error_from_errno("got_ref_to_str");
5262 printf("%s: %s\n", got_ref_get_name(re->ref), refstr);
5263 free(refstr);
5264 }
5265
5266 got_ref_list_free(&refs);
5267 return NULL((void *)0);
5268}
5269
5270static const struct got_error *
5271delete_ref(struct got_repository *repo, const char *refname)
5272{
5273 const struct got_error *err = NULL((void *)0);
5274 struct got_reference *ref;
5275
5276 err = got_ref_open(&ref, repo, refname, 0);
5277 if (err)
5278 return err;
5279
5280 err = got_ref_delete(ref, repo);
5281 got_ref_close(ref);
5282 return err;
5283}
5284
5285static const struct got_error *
5286add_ref(struct got_repository *repo, const char *refname, const char *target)
5287{
5288 const struct got_error *err = NULL((void *)0);
5289 struct got_object_id *id;
5290 struct got_reference *ref = NULL((void *)0);
5291
5292 /*
5293 * Don't let the user create a reference name with a leading '-'.
5294 * While technically a valid reference name, this case is usually
5295 * an unintended typo.
5296 */
5297 if (refname[0] == '-')
5298 return got_error_path(refname, GOT_ERR_REF_NAME_MINUS113);
5299
5300 err = got_repo_match_object_id_prefix(&id, target, GOT_OBJ_TYPE_ANY0,
5301 repo);
5302 if (err) {
5303 struct got_reference *target_ref;
5304
5305 if (err->code != GOT_ERR_BAD_OBJ_ID_STR23)
5306 return err;
5307 err = got_ref_open(&target_ref, repo, target, 0);
5308 if (err)
5309 return err;
5310 err = got_ref_resolve(&id, repo, target_ref);
5311 got_ref_close(target_ref);
5312 if (err)
5313 return err;
5314 }
5315
5316 err = got_ref_alloc(&ref, refname, id);
5317 if (err)
5318 goto done;
5319
5320 err = got_ref_write(ref, repo);
5321done:
5322 if (ref)
5323 got_ref_close(ref);
5324 free(id);
5325 return err;
5326}
5327
5328static const struct got_error *
5329add_symref(struct got_repository *repo, const char *refname, const char *target)
5330{
5331 const struct got_error *err = NULL((void *)0);
5332 struct got_reference *ref = NULL((void *)0);
5333 struct got_reference *target_ref = NULL((void *)0);
5334
5335 /*
5336 * Don't let the user create a reference name with a leading '-'.
5337 * While technically a valid reference name, this case is usually
5338 * an unintended typo.
5339 */
5340 if (refname[0] == '-')
5341 return got_error_path(refname, GOT_ERR_REF_NAME_MINUS113);
5342
5343 err = got_ref_open(&target_ref, repo, target, 0);
5344 if (err)
5345 return err;
5346
5347 err = got_ref_alloc_symref(&ref, refname, target_ref);
5348 if (err)
5349 goto done;
5350
5351 err = got_ref_write(ref, repo);
5352done:
5353 if (target_ref)
5354 got_ref_close(target_ref);
5355 if (ref)
5356 got_ref_close(ref);
5357 return err;
5358}
5359
5360static const struct got_error *
5361cmd_ref(int argc, char *argv[])
5362{
5363 const struct got_error *error = NULL((void *)0);
5364 struct got_repository *repo = NULL((void *)0);
5365 struct got_worktree *worktree = NULL((void *)0);
5366 char *cwd = NULL((void *)0), *repo_path = NULL((void *)0);
5367 int ch, do_list = 0, do_delete = 0;
5368 const char *obj_arg = NULL((void *)0), *symref_target= NULL((void *)0);
5369 char *refname = NULL((void *)0);
5370
5371 while ((ch = getopt(argc, argv, "c:dr:ls:")) != -1) {
5372 switch (ch) {
5373 case 'c':
5374 obj_arg = optarg;
5375 break;
5376 case 'd':
5377 do_delete = 1;
5378 break;
5379 case 'r':
5380 repo_path = realpath(optarg, NULL((void *)0));
5381 if (repo_path == NULL((void *)0))
5382 return got_error_from_errno2("realpath",
5383 optarg);
5384 got_path_strip_trailing_slashes(repo_path);
5385 break;
5386 case 'l':
5387 do_list = 1;
5388 break;
5389 case 's':
5390 symref_target = optarg;
5391 break;
5392 default:
5393 usage_ref();
5394 /* NOTREACHED */
5395 }
5396 }
5397
5398 if (obj_arg && do_list)
5399 option_conflict('c', 'l');
5400 if (obj_arg && do_delete)
5401 option_conflict('c', 'd');
5402 if (obj_arg && symref_target)
5403 option_conflict('c', 's');
5404 if (symref_target && do_delete)
5405 option_conflict('s', 'd');
5406 if (symref_target && do_list)
5407 option_conflict('s', 'l');
5408 if (do_delete && do_list)
5409 option_conflict('d', 'l');
5410
5411 argc -= optind;
5412 argv += optind;
5413
5414 if (do_list) {
5415 if (argc != 0 && argc != 1)
5416 usage_ref();
5417 if (argc == 1) {
5418 refname = strdup(argv[0]);
5419 if (refname == NULL((void *)0)) {
5420 error = got_error_from_errno("strdup");
5421 goto done;
5422 }
5423 }
5424 } else {
5425 if (argc != 1)
5426 usage_ref();
5427 refname = strdup(argv[0]);
5428 if (refname == NULL((void *)0)) {
5429 error = got_error_from_errno("strdup");
5430 goto done;
5431 }
5432 }
5433
5434 if (refname)
5435 got_path_strip_trailing_slashes(refname);
5436
5437#ifndef PROFILE
5438 if (do_list) {
5439 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
5440 NULL((void *)0)) == -1)
5441 err(1, "pledge");
5442 } else {
5443 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
5444 "sendfd unveil", NULL((void *)0)) == -1)
5445 err(1, "pledge");
5446 }
5447#endif
5448 cwd = getcwd(NULL((void *)0), 0);
5449 if (cwd == NULL((void *)0)) {
5450 error = got_error_from_errno("getcwd");
5451 goto done;
5452 }
5453
5454 if (repo_path == NULL((void *)0)) {
5455 error = got_worktree_open(&worktree, cwd);
5456 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
5457 goto done;
5458 else
5459 error = NULL((void *)0);
5460 if (worktree) {
5461 repo_path =
5462 strdup(got_worktree_get_repo_path(worktree));
5463 if (repo_path == NULL((void *)0))
5464 error = got_error_from_errno("strdup");
5465 if (error)
5466 goto done;
5467 } else {
5468 repo_path = strdup(cwd);
5469 if (repo_path == NULL((void *)0)) {
5470 error = got_error_from_errno("strdup");
5471 goto done;
5472 }
5473 }
5474 }
5475
5476 error = got_repo_open(&repo, repo_path, NULL((void *)0));
5477 if (error != NULL((void *)0))
5478 goto done;
5479
5480 error = apply_unveil(got_repo_get_path(repo), do_list,
5481 worktree ? got_worktree_get_root_path(worktree) : NULL((void *)0));
5482 if (error)
5483 goto done;
5484
5485 if (do_list)
5486 error = list_refs(repo, refname);
5487 else if (do_delete)
5488 error = delete_ref(repo, refname);
5489 else if (symref_target)
5490 error = add_symref(repo, refname, symref_target);
5491 else {
5492 if (obj_arg == NULL((void *)0))
5493 usage_ref();
5494 error = add_ref(repo, refname, obj_arg);
5495 }
5496done:
5497 free(refname);
5498 if (repo)
5499 got_repo_close(repo);
5500 if (worktree)
5501 got_worktree_close(worktree);
5502 free(cwd);
5503 free(repo_path);
5504 return error;
5505}
5506
5507__dead__attribute__((__noreturn__)) static void
5508usage_branch(void)
5509{
5510 fprintf(stderr(&__sF[2]),
5511 "usage: %s branch [-c commit] [-d] [-r repository] [-l] [-n] "
5512 "[name]\n", getprogname());
5513 exit(1);
5514}
5515
5516static const struct got_error *
5517list_branch(struct got_repository *repo, struct got_worktree *worktree,
5518 struct got_reference *ref)
5519{
5520 const struct got_error *err = NULL((void *)0);
5521 const char *refname, *marker = " ";
5522 char *refstr;
5523
5524 refname = got_ref_get_name(ref);
5525 if (worktree && strcmp(refname,
5526 got_worktree_get_head_ref_name(worktree)) == 0) {
5527 struct got_object_id *id = NULL((void *)0);
5528
5529 err = got_ref_resolve(&id, repo, ref);
5530 if (err)
5531 return err;
5532 if (got_object_id_cmp(id,
5533 got_worktree_get_base_commit_id(worktree)) == 0)
5534 marker = "* ";
5535 else
5536 marker = "~ ";
5537 free(id);
5538 }
5539
5540 if (strncmp(refname, "refs/heads/", 11) == 0)
5541 refname += 11;
5542 if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5543 refname += 18;
5544 if (strncmp(refname, "refs/remotes/", 13) == 0)
5545 refname += 13;
5546
5547 refstr = got_ref_to_str(ref);
5548 if (refstr == NULL((void *)0))
5549 return got_error_from_errno("got_ref_to_str");
5550
5551 printf("%s%s: %s\n", marker, refname, refstr);
5552 free(refstr);
5553 return NULL((void *)0);
5554}
5555
5556static const struct got_error *
5557show_current_branch(struct got_repository *repo, struct got_worktree *worktree)
5558{
5559 const char *refname;
5560
5561 if (worktree == NULL((void *)0))
5562 return got_error(GOT_ERR_NOT_WORKTREE60);
5563
5564 refname = got_worktree_get_head_ref_name(worktree);
5565
5566 if (strncmp(refname, "refs/heads/", 11) == 0)
5567 refname += 11;
5568 if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5569 refname += 18;
5570
5571 printf("%s\n", refname);
5572
5573 return NULL((void *)0);
5574}
5575
5576static const struct got_error *
5577list_branches(struct got_repository *repo, struct got_worktree *worktree)
5578{
5579 static const struct got_error *err = NULL((void *)0);
5580 struct got_reflist_head refs;
5581 struct got_reflist_entry *re;
5582 struct got_reference *temp_ref = NULL((void *)0);
5583 int rebase_in_progress, histedit_in_progress;
5584
5585 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
5586
5587 if (worktree) {
5588 err = got_worktree_rebase_in_progress(&rebase_in_progress,
5589 worktree);
5590 if (err)
5591 return err;
5592
5593 err = got_worktree_histedit_in_progress(&histedit_in_progress,
5594 worktree);
5595 if (err)
5596 return err;
5597
5598 if (rebase_in_progress || histedit_in_progress) {
5599 err = got_ref_open(&temp_ref, repo,
5600 got_worktree_get_head_ref_name(worktree), 0);
5601 if (err)
5602 return err;
5603 list_branch(repo, worktree, temp_ref);
5604 got_ref_close(temp_ref);
5605 }
5606 }
5607
5608 err = got_ref_list(&refs, repo, "refs/heads",
5609 got_ref_cmp_by_name, NULL((void *)0));
5610 if (err)
5611 return err;
5612
5613 TAILQ_FOREACH(re, &refs, entry)for((re) = ((&refs)->tqh_first); (re) != ((void *)0); (
re) = ((re)->entry.tqe_next))
5614 list_branch(repo, worktree, re->ref);
5615
5616 got_ref_list_free(&refs);
5617
5618 err = got_ref_list(&refs, repo, "refs/remotes",
5619 got_ref_cmp_by_name, NULL((void *)0));
5620 if (err)
5621 return err;
5622
5623 TAILQ_FOREACH(re, &refs, entry)for((re) = ((&refs)->tqh_first); (re) != ((void *)0); (
re) = ((re)->entry.tqe_next))
5624 list_branch(repo, worktree, re->ref);
5625
5626 got_ref_list_free(&refs);
5627
5628 return NULL((void *)0);
5629}
5630
5631static const struct got_error *
5632delete_branch(struct got_repository *repo, struct got_worktree *worktree,
5633 const char *branch_name)
5634{
5635 const struct got_error *err = NULL((void *)0);
5636 struct got_reference *ref = NULL((void *)0);
5637 char *refname;
5638
5639 if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
5640 return got_error_from_errno("asprintf");
5641
5642 err = got_ref_open(&ref, repo, refname, 0);
5643 if (err)
5644 goto done;
5645
5646 if (worktree &&
5647 strcmp(got_worktree_get_head_ref_name(worktree),
5648 got_ref_get_name(ref)) == 0) {
5649 err = got_error_msg(GOT_ERR_SAME_BRANCH79,
5650 "will not delete this work tree's current branch");
5651 goto done;
5652 }
5653
5654 err = got_ref_delete(ref, repo);
5655done:
5656 if (ref)
5657 got_ref_close(ref);
5658 free(refname);
5659 return err;
5660}
5661
5662static const struct got_error *
5663add_branch(struct got_repository *repo, const char *branch_name,
5664 struct got_object_id *base_commit_id)
5665{
5666 const struct got_error *err = NULL((void *)0);
5667 struct got_reference *ref = NULL((void *)0);
5668 char *base_refname = NULL((void *)0), *refname = NULL((void *)0);
5669
5670 /*
5671 * Don't let the user create a branch name with a leading '-'.
5672 * While technically a valid reference name, this case is usually
5673 * an unintended typo.
5674 */
5675 if (branch_name[0] == '-')
5676 return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS113);
5677
5678 if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
5679 err = got_error_from_errno("asprintf");
5680 goto done;
5681 }
5682
5683 err = got_ref_open(&ref, repo, refname, 0);
5684 if (err == NULL((void *)0)) {
5685 err = got_error(GOT_ERR_BRANCH_EXISTS83);
5686 goto done;
5687 } else if (err->code != GOT_ERR_NOT_REF5)
5688 goto done;
5689
5690 err = got_ref_alloc(&ref, refname, base_commit_id);
5691 if (err)
5692 goto done;
5693
5694 err = got_ref_write(ref, repo);
5695done:
5696 if (ref)
5697 got_ref_close(ref);
5698 free(base_refname);
5699 free(refname);
5700 return err;
5701}
5702
5703static const struct got_error *
5704cmd_branch(int argc, char *argv[])
5705{
5706 const struct got_error *error = NULL((void *)0);
5707 struct got_repository *repo = NULL((void *)0);
5708 struct got_worktree *worktree = NULL((void *)0);
5709 char *cwd = NULL((void *)0), *repo_path = NULL((void *)0);
5710 int ch, do_list = 0, do_show = 0, do_update = 1;
5711 const char *delref = NULL((void *)0), *commit_id_arg = NULL((void *)0);
5712 struct got_reference *ref = NULL((void *)0);
5713 struct got_pathlist_head paths;
5714 struct got_pathlist_entry *pe;
5715 struct got_object_id *commit_id = NULL((void *)0);
5716 char *commit_id_str = NULL((void *)0);
5717
5718 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
5719
5720 while ((ch = getopt(argc, argv, "c:d:r:ln")) != -1) {
5721 switch (ch) {
5722 case 'c':
5723 commit_id_arg = optarg;
5724 break;
5725 case 'd':
5726 delref = optarg;
5727 break;
5728 case 'r':
5729 repo_path = realpath(optarg, NULL((void *)0));
5730 if (repo_path == NULL((void *)0))
5731 return got_error_from_errno2("realpath",
5732 optarg);
5733 got_path_strip_trailing_slashes(repo_path);
5734 break;
5735 case 'l':
5736 do_list = 1;
5737 break;
5738 case 'n':
5739 do_update = 0;
5740 break;
5741 default:
5742 usage_branch();
5743 /* NOTREACHED */
5744 }
5745 }
5746
5747 if (do_list && delref)
5748 option_conflict('l', 'd');
5749
5750 argc -= optind;
5751 argv += optind;
5752
5753 if (!do_list && !delref && argc == 0)
5754 do_show = 1;
5755
5756 if ((do_list || delref || do_show) && commit_id_arg != NULL((void *)0))
5757 errx(1, "-c option can only be used when creating a branch");
5758
5759 if (do_list || delref) {
5760 if (argc > 0)
5761 usage_branch();
5762 } else if (!do_show && argc != 1)
5763 usage_branch();
5764
5765#ifndef PROFILE
5766 if (do_list || do_show) {
5767 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
5768 NULL((void *)0)) == -1)
5769 err(1, "pledge");
5770 } else {
5771 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
5772 "sendfd unveil", NULL((void *)0)) == -1)
5773 err(1, "pledge");
5774 }
5775#endif
5776 cwd = getcwd(NULL((void *)0), 0);
5777 if (cwd == NULL((void *)0)) {
5778 error = got_error_from_errno("getcwd");
5779 goto done;
5780 }
5781
5782 if (repo_path == NULL((void *)0)) {
5783 error = got_worktree_open(&worktree, cwd);
5784 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
5785 goto done;
5786 else
5787 error = NULL((void *)0);
5788 if (worktree) {
5789 repo_path =
5790 strdup(got_worktree_get_repo_path(worktree));
5791 if (repo_path == NULL((void *)0))
5792 error = got_error_from_errno("strdup");
5793 if (error)
5794 goto done;
5795 } else {
5796 repo_path = strdup(cwd);
5797 if (repo_path == NULL((void *)0)) {
5798 error = got_error_from_errno("strdup");
5799 goto done;
5800 }
5801 }
5802 }
5803
5804 error = got_repo_open(&repo, repo_path, NULL((void *)0));
5805 if (error != NULL((void *)0))
5806 goto done;
5807
5808 error = apply_unveil(got_repo_get_path(repo), do_list,
5809 worktree ? got_worktree_get_root_path(worktree) : NULL((void *)0));
5810 if (error)
5811 goto done;
5812
5813 if (do_show)
5814 error = show_current_branch(repo, worktree);
5815 else if (do_list)
5816 error = list_branches(repo, worktree);
5817 else if (delref)
5818 error = delete_branch(repo, worktree, delref);
5819 else {
5820 struct got_reflist_head refs;
5821 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
5822 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name,
5823 NULL((void *)0));
5824 if (error)
5825 goto done;
5826 if (commit_id_arg == NULL((void *)0))
5827 commit_id_arg = worktree ?
5828 got_worktree_get_head_ref_name(worktree) :
5829 GOT_REF_HEAD"HEAD";
5830 error = got_repo_match_object_id(&commit_id, NULL((void *)0),
5831 commit_id_arg, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
5832 got_ref_list_free(&refs);
5833 if (error)
5834 goto done;
5835 error = add_branch(repo, argv[0], commit_id);
5836 if (error)
5837 goto done;
5838 if (worktree && do_update) {
5839 struct got_update_progress_arg upa;
5840 char *branch_refname = NULL((void *)0);
5841
5842 error = got_object_id_str(&commit_id_str, commit_id);
5843 if (error)
5844 goto done;
5845 error = get_worktree_paths_from_argv(&paths, 0, NULL((void *)0),
5846 worktree);
5847 if (error)
5848 goto done;
5849 if (asprintf(&branch_refname, "refs/heads/%s", argv[0])
5850 == -1) {
5851 error = got_error_from_errno("asprintf");
5852 goto done;
5853 }
5854 error = got_ref_open(&ref, repo, branch_refname, 0);
5855 free(branch_refname);
5856 if (error)
5857 goto done;
5858 error = switch_head_ref(ref, commit_id, worktree,
5859 repo);
5860 if (error)
5861 goto done;
5862 error = got_worktree_set_base_commit_id(worktree, repo,
5863 commit_id);
5864 if (error)
5865 goto done;
5866 memset(&upa, 0, sizeof(upa));
5867 error = got_worktree_checkout_files(worktree, &paths,
5868 repo, update_progress, &upa, check_cancelled,
5869 NULL((void *)0));
5870 if (error)
5871 goto done;
5872 if (upa.did_something)
5873 printf("Updated to commit %s\n", commit_id_str);
5874 print_update_progress_stats(&upa);
5875 }
5876 }
5877done:
5878 if (ref)
5879 got_ref_close(ref);
5880 if (repo)
5881 got_repo_close(repo);
5882 if (worktree)
5883 got_worktree_close(worktree);
5884 free(cwd);
5885 free(repo_path);
5886 free(commit_id);
5887 free(commit_id_str);
5888 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
5889 free((char *)pe->path);
5890 got_pathlist_free(&paths);
5891 return error;
5892}
5893
5894
5895__dead__attribute__((__noreturn__)) static void
5896usage_tag(void)
5897{
5898 fprintf(stderr(&__sF[2]),
5899 "usage: %s tag [-c commit] [-r repository] [-l] "
5900 "[-m message] name\n", getprogname());
5901 exit(1);
5902}
5903
5904#if 0
5905static const struct got_error *
5906sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags)
5907{
5908 const struct got_error *err = NULL((void *)0);
5909 struct got_reflist_entry *re, *se, *new;
5910 struct got_object_id *re_id, *se_id;
5911 struct got_tag_object *re_tag, *se_tag;
5912 time_t re_time, se_time;
5913
5914 SIMPLEQ_FOREACH(re, tags, entry)for((re) = ((tags)->sqh_first); (re) != ((void *)0); (re) =
((re)->entry.sqe_next))
{
5915 se = SIMPLEQ_FIRST(sorted)((sorted)->sqh_first);
5916 if (se == NULL((void *)0)) {
5917 err = got_reflist_entry_dup(&new, re);
5918 if (err)
5919 return err;
5920 SIMPLEQ_INSERT_HEAD(sorted, new, entry)do { if (((new)->entry.sqe_next = (sorted)->sqh_first) ==
((void *)0)) (sorted)->sqh_last = &(new)->entry.sqe_next
; (sorted)->sqh_first = (new); } while (0)
;
5921 continue;
5922 } else {
5923 err = got_ref_resolve(&re_id, repo, re->ref);
5924 if (err)
5925 break;
5926 err = got_object_open_as_tag(&re_tag, repo, re_id);
5927 free(re_id);
5928 if (err)
5929 break;
5930 re_time = got_object_tag_get_tagger_time(re_tag);
5931 got_object_tag_close(re_tag);
5932 }
5933
5934 while (se) {
5935 err = got_ref_resolve(&se_id, repo, re->ref);
5936 if (err)
5937 break;
5938 err = got_object_open_as_tag(&se_tag, repo, se_id);
5939 free(se_id);
5940 if (err)
5941 break;
5942 se_time = got_object_tag_get_tagger_time(se_tag);
5943 got_object_tag_close(se_tag);
5944
5945 if (se_time > re_time) {
5946 err = got_reflist_entry_dup(&new, re);
5947 if (err)
5948 return err;
5949 SIMPLEQ_INSERT_AFTER(sorted, se, new, entry)do { if (((new)->entry.sqe_next = (se)->entry.sqe_next)
== ((void *)0)) (sorted)->sqh_last = &(new)->entry
.sqe_next; (se)->entry.sqe_next = (new); } while (0)
;
5950 break;
5951 }
5952 se = SIMPLEQ_NEXT(se, entry)((se)->entry.sqe_next);
5953 continue;
5954 }
5955 }
5956done:
5957 return err;
5958}
5959#endif
5960
5961static const struct got_error *
5962list_tags(struct got_repository *repo, struct got_worktree *worktree)
5963{
5964 static const struct got_error *err = NULL((void *)0);
5965 struct got_reflist_head refs;
5966 struct got_reflist_entry *re;
5967
5968 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
5969
5970 err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo);
5971 if (err)
5972 return err;
5973
5974 TAILQ_FOREACH(re, &refs, entry)for((re) = ((&refs)->tqh_first); (re) != ((void *)0); (
re) = ((re)->entry.tqe_next))
{
5975 const char *refname;
5976 char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr;
5977 char datebuf[26];
5978 const char *tagger;
5979 time_t tagger_time;
5980 struct got_object_id *id;
5981 struct got_tag_object *tag;
5982 struct got_commit_object *commit = NULL((void *)0);
5983
5984 refname = got_ref_get_name(re->ref);
5985 if (strncmp(refname, "refs/tags/", 10) != 0)
5986 continue;
5987 refname += 10;
5988 refstr = got_ref_to_str(re->ref);
5989 if (refstr == NULL((void *)0)) {
5990 err = got_error_from_errno("got_ref_to_str");
5991 break;
5992 }
5993 printf("%stag %s %s\n", GOT_COMMIT_SEP_STR"-----------------------------------------------\n", refname, refstr);
5994 free(refstr);
5995
5996 err = got_ref_resolve(&id, repo, re->ref);
5997 if (err)
5998 break;
5999 err = got_object_open_as_tag(&tag, repo, id);
6000 if (err) {
6001 if (err->code != GOT_ERR_OBJ_TYPE11) {
6002 free(id);
6003 break;
6004 }
6005 /* "lightweight" tag */
6006 err = got_object_open_as_commit(&commit, repo, id);
6007 if (err) {
6008 free(id);
6009 break;
6010 }
6011 tagger = got_object_commit_get_committer(commit);
6012 tagger_time =
6013 got_object_commit_get_committer_time(commit);
6014 err = got_object_id_str(&id_str, id);
6015 free(id);
6016 if (err)
6017 break;
6018 } else {
6019 free(id);
6020 tagger = got_object_tag_get_tagger(tag);
6021 tagger_time = got_object_tag_get_tagger_time(tag);
6022 err = got_object_id_str(&id_str,
6023 got_object_tag_get_object_id(tag));
6024 if (err)
6025 break;
6026 }
6027 printf("from: %s\n", tagger);
6028 datestr = get_datestr(&tagger_time, datebuf);
6029 if (datestr)
6030 printf("date: %s UTC\n", datestr);
6031 if (commit)
6032 printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT"commit", id_str);
6033 else {
6034 switch (got_object_tag_get_object_type(tag)) {
6035 case GOT_OBJ_TYPE_BLOB3:
6036 printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB"blob",
6037 id_str);
6038 break;
6039 case GOT_OBJ_TYPE_TREE2:
6040 printf("object: %s %s\n", GOT_OBJ_LABEL_TREE"tree",
6041 id_str);
6042 break;
6043 case GOT_OBJ_TYPE_COMMIT1:
6044 printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT"commit",
6045 id_str);
6046 break;
6047 case GOT_OBJ_TYPE_TAG4:
6048 printf("object: %s %s\n", GOT_OBJ_LABEL_TAG"tag",
6049 id_str);
6050 break;
6051 default:
6052 break;
6053 }
6054 }
6055 free(id_str);
6056 if (commit) {
6057 err = got_object_commit_get_logmsg(&tagmsg0, commit);
6058 if (err)
6059 break;
6060 got_object_commit_close(commit);
6061 } else {
6062 tagmsg0 = strdup(got_object_tag_get_message(tag));
6063 got_object_tag_close(tag);
6064 if (tagmsg0 == NULL((void *)0)) {
6065 err = got_error_from_errno("strdup");
6066 break;
6067 }
6068 }
6069
6070 tagmsg = tagmsg0;
6071 do {
6072 line = strsep(&tagmsg, "\n");
6073 if (line)
6074 printf(" %s\n", line);
6075 } while (line);
6076 free(tagmsg0);
6077 }
6078
6079 got_ref_list_free(&refs);
6080 return NULL((void *)0);
6081}
6082
6083static const struct got_error *
6084get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str,
6085 const char *tag_name, const char *repo_path)
6086{
6087 const struct got_error *err = NULL((void *)0);
6088 char *template = NULL((void *)0), *initial_content = NULL((void *)0);
6089 char *editor = NULL((void *)0);
6090 int initial_content_len;
6091 int fd = -1;
6092
6093 if (asprintf(&template, GOT_TMPDIR_STR"/tmp" "/got-tagmsg") == -1) {
6094 err = got_error_from_errno("asprintf");
6095 goto done;
6096 }
6097
6098 initial_content_len = asprintf(&initial_content,
6099 "\n# tagging commit %s as %s\n",
6100 commit_id_str, tag_name);
6101 if (initial_content_len == -1) {
6102 err = got_error_from_errno("asprintf");
6103 goto done;
6104 }
6105
6106 err = got_opentemp_named_fd(tagmsg_path, &fd, template);
6107 if (err)
6108 goto done;
6109
6110 if (write(fd, initial_content, initial_content_len) == -1) {
6111 err = got_error_from_errno2("write", *tagmsg_path);
6112 goto done;
6113 }
6114
6115 err = get_editor(&editor);
6116 if (err)
6117 goto done;
6118 err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content,
6119 initial_content_len, 1);
6120done:
6121 free(initial_content);
6122 free(template);
6123 free(editor);
6124
6125 if (fd != -1 && close(fd) == -1 && err == NULL((void *)0))
6126 err = got_error_from_errno2("close", *tagmsg_path);
6127
6128 /* Editor is done; we can now apply unveil(2) */
6129 if (err == NULL((void *)0))
6130 err = apply_unveil(repo_path, 0, NULL((void *)0));
6131 if (err) {
6132 free(*tagmsg);
6133 *tagmsg = NULL((void *)0);
6134 }
6135 return err;
6136}
6137
6138static const struct got_error *
6139add_tag(struct got_repository *repo, struct got_worktree *worktree,
6140 const char *tag_name, const char *commit_arg, const char *tagmsg_arg)
6141{
6142 const struct got_error *err = NULL((void *)0);
6143 struct got_object_id *commit_id = NULL((void *)0), *tag_id = NULL((void *)0);
6144 char *label = NULL((void *)0), *commit_id_str = NULL((void *)0);
6145 struct got_reference *ref = NULL((void *)0);
6146 char *refname = NULL((void *)0), *tagmsg = NULL((void *)0), *tagger = NULL((void *)0);
6147 char *tagmsg_path = NULL((void *)0), *tag_id_str = NULL((void *)0);
6148 int preserve_tagmsg = 0;
6149 struct got_reflist_head refs;
6150
6151 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
6152
6153 /*
6154 * Don't let the user create a tag name with a leading '-'.
6155 * While technically a valid reference name, this case is usually
6156 * an unintended typo.
6157 */
6158 if (tag_name[0] == '-')
6159 return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS113);
6160
6161 err = get_author(&tagger, repo, worktree);
6162 if (err)
6163 return err;
6164
6165 err = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name, NULL((void *)0));
6166 if (err)
6167 goto done;
6168
6169 err = got_repo_match_object_id(&commit_id, &label, commit_arg,
6170 GOT_OBJ_TYPE_COMMIT1, &refs, repo);
6171 if (err)
6172 goto done;
6173
6174 err = got_object_id_str(&commit_id_str, commit_id);
6175 if (err)
6176 goto done;
6177
6178 if (strncmp("refs/tags/", tag_name, 10) == 0) {
6179 refname = strdup(tag_name);
6180 if (refname == NULL((void *)0)) {
6181 err = got_error_from_errno("strdup");
6182 goto done;
6183 }
6184 tag_name += 10;
6185 } else if (asprintf(&refname, "refs/tags/%s", tag_name) == -1) {
6186 err = got_error_from_errno("asprintf");
6187 goto done;
6188 }
6189
6190 err = got_ref_open(&ref, repo, refname, 0);
6191 if (err == NULL((void *)0)) {
6192 err = got_error(GOT_ERR_TAG_EXISTS109);
6193 goto done;
6194 } else if (err->code != GOT_ERR_NOT_REF5)
6195 goto done;
6196
6197 if (tagmsg_arg == NULL((void *)0)) {
6198 err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str,
6199 tag_name, got_repo_get_path(repo));
6200 if (err) {
6201 if (err->code != GOT_ERR_COMMIT_MSG_EMPTY74 &&
6202 tagmsg_path != NULL((void *)0))
6203 preserve_tagmsg = 1;
6204 goto done;
6205 }
6206 }
6207
6208 err = got_object_tag_create(&tag_id, tag_name, commit_id,
6209 tagger, time(NULL((void *)0)), tagmsg ? tagmsg : tagmsg_arg, repo);
6210 if (err) {
6211 if (tagmsg_path)
6212 preserve_tagmsg = 1;
6213 goto done;
6214 }
6215
6216 err = got_ref_alloc(&ref, refname, tag_id);
6217 if (err) {
6218 if (tagmsg_path)
6219 preserve_tagmsg = 1;
6220 goto done;
6221 }
6222
6223 err = got_ref_write(ref, repo);
6224 if (err) {
6225 if (tagmsg_path)
6226 preserve_tagmsg = 1;
6227 goto done;
6228 }
6229
6230 err = got_object_id_str(&tag_id_str, tag_id);
6231 if (err) {
6232 if (tagmsg_path)
6233 preserve_tagmsg = 1;
6234 goto done;
6235 }
6236 printf("Created tag %s\n", tag_id_str);
6237done:
6238 if (preserve_tagmsg) {
6239 fprintf(stderr(&__sF[2]), "%s: tag message preserved in %s\n",
6240 getprogname(), tagmsg_path);
6241 } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL((void *)0))
6242 err = got_error_from_errno2("unlink", tagmsg_path);
6243 free(tag_id_str);
6244 if (ref)
6245 got_ref_close(ref);
6246 free(commit_id);
6247 free(commit_id_str);
6248 free(refname);
6249 free(tagmsg);
6250 free(tagmsg_path);
6251 free(tagger);
6252 got_ref_list_free(&refs);
6253 return err;
6254}
6255
6256static const struct got_error *
6257cmd_tag(int argc, char *argv[])
6258{
6259 const struct got_error *error = NULL((void *)0);
6260 struct got_repository *repo = NULL((void *)0);
6261 struct got_worktree *worktree = NULL((void *)0);
6262 char *cwd = NULL((void *)0), *repo_path = NULL((void *)0), *commit_id_str = NULL((void *)0);
6263 char *gitconfig_path = NULL((void *)0);
6264 const char *tag_name, *commit_id_arg = NULL((void *)0), *tagmsg = NULL((void *)0);
6265 int ch, do_list = 0;
6266
6267 while ((ch = getopt(argc, argv, "c:m:r:l")) != -1) {
6268 switch (ch) {
6269 case 'c':
6270 commit_id_arg = optarg;
6271 break;
6272 case 'm':
6273 tagmsg = optarg;
6274 break;
6275 case 'r':
6276 repo_path = realpath(optarg, NULL((void *)0));
6277 if (repo_path == NULL((void *)0))
6278 return got_error_from_errno2("realpath",
6279 optarg);
6280 got_path_strip_trailing_slashes(repo_path);
6281 break;
6282 case 'l':
6283 do_list = 1;
6284 break;
6285 default:
6286 usage_tag();
6287 /* NOTREACHED */
6288 }
6289 }
6290
6291 argc -= optind;
6292 argv += optind;
6293
6294 if (do_list) {
6295 if (commit_id_arg != NULL((void *)0))
6296 errx(1,
6297 "-c option can only be used when creating a tag");
6298 if (tagmsg)
6299 option_conflict('l', 'm');
6300 if (argc > 0)
6301 usage_tag();
6302 } else if (argc != 1)
6303 usage_tag();
6304
6305 tag_name = argv[0];
6306
6307#ifndef PROFILE
6308 if (do_list) {
6309 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6310 NULL((void *)0)) == -1)
6311 err(1, "pledge");
6312 } else {
6313 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6314 "sendfd unveil", NULL((void *)0)) == -1)
6315 err(1, "pledge");
6316 }
6317#endif
6318 cwd = getcwd(NULL((void *)0), 0);
6319 if (cwd == NULL((void *)0)) {
6320 error = got_error_from_errno("getcwd");
6321 goto done;
6322 }
6323
6324 if (repo_path == NULL((void *)0)) {
6325 error = got_worktree_open(&worktree, cwd);
6326 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
6327 goto done;
6328 else
6329 error = NULL((void *)0);
6330 if (worktree) {
6331 repo_path =
6332 strdup(got_worktree_get_repo_path(worktree));
6333 if (repo_path == NULL((void *)0))
6334 error = got_error_from_errno("strdup");
6335 if (error)
6336 goto done;
6337 } else {
6338 repo_path = strdup(cwd);
6339 if (repo_path == NULL((void *)0)) {
6340 error = got_error_from_errno("strdup");
6341 goto done;
6342 }
6343 }
6344 }
6345
6346 if (do_list) {
6347 error = got_repo_open(&repo, repo_path, NULL((void *)0));
6348 if (error != NULL((void *)0))
6349 goto done;
6350 error = apply_unveil(got_repo_get_path(repo), 1, NULL((void *)0));
6351 if (error)
6352 goto done;
6353 error = list_tags(repo, worktree);
6354 } else {
6355 error = get_gitconfig_path(&gitconfig_path);
6356 if (error)
6357 goto done;
6358 error = got_repo_open(&repo, repo_path, gitconfig_path);
6359 if (error != NULL((void *)0))
6360 goto done;
6361
6362 if (tagmsg) {
6363 error = apply_unveil(got_repo_get_path(repo), 0, NULL((void *)0));
6364 if (error)
6365 goto done;
6366 }
6367
6368 if (commit_id_arg == NULL((void *)0)) {
6369 struct got_reference *head_ref;
6370 struct got_object_id *commit_id;
6371 error = got_ref_open(&head_ref, repo,
6372 worktree ? got_worktree_get_head_ref_name(worktree)
6373 : GOT_REF_HEAD"HEAD", 0);
6374 if (error)
6375 goto done;
6376 error = got_ref_resolve(&commit_id, repo, head_ref);
6377 got_ref_close(head_ref);
6378 if (error)
6379 goto done;
6380 error = got_object_id_str(&commit_id_str, commit_id);
6381 free(commit_id);
6382 if (error)
6383 goto done;
6384 }
6385
6386 error = add_tag(repo, worktree, tag_name,
6387 commit_id_str ? commit_id_str : commit_id_arg, tagmsg);
6388 }
6389done:
6390 if (repo)
6391 got_repo_close(repo);
6392 if (worktree)
6393 got_worktree_close(worktree);
6394 free(cwd);
6395 free(repo_path);
6396 free(gitconfig_path);
6397 free(commit_id_str);
6398 return error;
6399}
6400
6401__dead__attribute__((__noreturn__)) static void
6402usage_add(void)
6403{
6404 fprintf(stderr(&__sF[2]), "usage: %s add [-R] [-I] path ...\n",
6405 getprogname());
6406 exit(1);
6407}
6408
6409static const struct got_error *
6410add_progress(void *arg, unsigned char status, const char *path)
6411{
6412 while (path[0] == '/')
6413 path++;
6414 printf("%c %s\n", status, path);
6415 return NULL((void *)0);
6416}
6417
6418static const struct got_error *
6419cmd_add(int argc, char *argv[])
6420{
6421 const struct got_error *error = NULL((void *)0);
6422 struct got_repository *repo = NULL((void *)0);
6423 struct got_worktree *worktree = NULL((void *)0);
6424 char *cwd = NULL((void *)0);
6425 struct got_pathlist_head paths;
6426 struct got_pathlist_entry *pe;
6427 int ch, can_recurse = 0, no_ignores = 0;
6428
6429 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
6430
6431 while ((ch = getopt(argc, argv, "IR")) != -1) {
6432 switch (ch) {
6433 case 'I':
6434 no_ignores = 1;
6435 break;
6436 case 'R':
6437 can_recurse = 1;
6438 break;
6439 default:
6440 usage_add();
6441 /* NOTREACHED */
6442 }
6443 }
6444
6445 argc -= optind;
6446 argv += optind;
6447
6448#ifndef PROFILE
6449 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6450 NULL((void *)0)) == -1)
6451 err(1, "pledge");
6452#endif
6453 if (argc < 1)
6454 usage_add();
6455
6456 cwd = getcwd(NULL((void *)0), 0);
6457 if (cwd == NULL((void *)0)) {
6458 error = got_error_from_errno("getcwd");
6459 goto done;
6460 }
6461
6462 error = got_worktree_open(&worktree, cwd);
6463 if (error) {
6464 if (error->code == GOT_ERR_NOT_WORKTREE60)
6465 error = wrap_not_worktree_error(error, "add", cwd);
6466 goto done;
6467 }
6468
6469 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6470 NULL((void *)0));
6471 if (error != NULL((void *)0))
6472 goto done;
6473
6474 error = apply_unveil(got_repo_get_path(repo), 1,
6475 got_worktree_get_root_path(worktree));
6476 if (error)
6477 goto done;
6478
6479 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6480 if (error)
6481 goto done;
6482
6483 if (!can_recurse && no_ignores) {
6484 error = got_error_msg(GOT_ERR_BAD_PATH4,
6485 "disregarding ignores requires -R option");
6486 goto done;
6487
6488 }
6489
6490 if (!can_recurse) {
6491 char *ondisk_path;
6492 struct stat sb;
6493 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
{
6494 if (asprintf(&ondisk_path, "%s/%s",
6495 got_worktree_get_root_path(worktree),
6496 pe->path) == -1) {
6497 error = got_error_from_errno("asprintf");
6498 goto done;
6499 }
6500 if (lstat(ondisk_path, &sb) == -1) {
6501 if (errno(*__errno()) == ENOENT2) {
6502 free(ondisk_path);
6503 continue;
6504 }
6505 error = got_error_from_errno2("lstat",
6506 ondisk_path);
6507 free(ondisk_path);
6508 goto done;
6509 }
6510 free(ondisk_path);
6511 if (S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000)) {
6512 error = got_error_msg(GOT_ERR_BAD_PATH4,
6513 "adding directories requires -R option");
6514 goto done;
6515 }
6516 }
6517 }
6518
6519 error = got_worktree_schedule_add(worktree, &paths, add_progress,
6520 NULL((void *)0), repo, no_ignores);
6521done:
6522 if (repo)
6523 got_repo_close(repo);
6524 if (worktree)
6525 got_worktree_close(worktree);
6526 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
6527 free((char *)pe->path);
6528 got_pathlist_free(&paths);
6529 free(cwd);
6530 return error;
6531}
6532
6533__dead__attribute__((__noreturn__)) static void
6534usage_remove(void)
6535{
6536 fprintf(stderr(&__sF[2]), "usage: %s remove [-f] [-k] [-R] [-s status-codes] "
6537 "path ...\n", getprogname());
6538 exit(1);
6539}
6540
6541static const struct got_error *
6542print_remove_status(void *arg, unsigned char status,
6543 unsigned char staged_status, const char *path)
6544{
6545 while (path[0] == '/')
6546 path++;
6547 if (status == GOT_STATUS_NONEXISTENT'N')
6548 return NULL((void *)0);
6549 if (status == staged_status && (status == GOT_STATUS_DELETE'D'))
6550 status = GOT_STATUS_NO_CHANGE' ';
6551 printf("%c%c %s\n", status, staged_status, path);
6552 return NULL((void *)0);
6553}
6554
6555static const struct got_error *
6556cmd_remove(int argc, char *argv[])
6557{
6558 const struct got_error *error = NULL((void *)0);
6559 struct got_worktree *worktree = NULL((void *)0);
6560 struct got_repository *repo = NULL((void *)0);
6561 const char *status_codes = NULL((void *)0);
6562 char *cwd = NULL((void *)0);
6563 struct got_pathlist_head paths;
6564 struct got_pathlist_entry *pe;
6565 int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i;
6566
6567 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
6568
6569 while ((ch = getopt(argc, argv, "fkRs:")) != -1) {
6570 switch (ch) {
6571 case 'f':
6572 delete_local_mods = 1;
6573 break;
6574 case 'k':
6575 keep_on_disk = 1;
6576 break;
6577 case 'R':
6578 can_recurse = 1;
6579 break;
6580 case 's':
6581 for (i = 0; i < strlen(optarg); i++) {
6582 switch (optarg[i]) {
6583 case GOT_STATUS_MODIFY'M':
6584 delete_local_mods = 1;
6585 break;
6586 case GOT_STATUS_MISSING'!':
6587 break;
6588 default:
6589 errx(1, "invalid status code '%c'",
6590 optarg[i]);
6591 }
6592 }
6593 status_codes = optarg;
6594 break;
6595 default:
6596 usage_remove();
6597 /* NOTREACHED */
6598 }
6599 }
6600
6601 argc -= optind;
6602 argv += optind;
6603
6604#ifndef PROFILE
6605 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6606 NULL((void *)0)) == -1)
6607 err(1, "pledge");
6608#endif
6609 if (argc < 1)
6610 usage_remove();
6611
6612 cwd = getcwd(NULL((void *)0), 0);
6613 if (cwd == NULL((void *)0)) {
6614 error = got_error_from_errno("getcwd");
6615 goto done;
6616 }
6617 error = got_worktree_open(&worktree, cwd);
6618 if (error) {
6619 if (error->code == GOT_ERR_NOT_WORKTREE60)
6620 error = wrap_not_worktree_error(error, "remove", cwd);
6621 goto done;
6622 }
6623
6624 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6625 NULL((void *)0));
6626 if (error)
6627 goto done;
6628
6629 error = apply_unveil(got_repo_get_path(repo), 1,
6630 got_worktree_get_root_path(worktree));
6631 if (error)
6632 goto done;
6633
6634 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6635 if (error)
6636 goto done;
6637
6638 if (!can_recurse) {
6639 char *ondisk_path;
6640 struct stat sb;
6641 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
{
6642 if (asprintf(&ondisk_path, "%s/%s",
6643 got_worktree_get_root_path(worktree),
6644 pe->path) == -1) {
6645 error = got_error_from_errno("asprintf");
6646 goto done;
6647 }
6648 if (lstat(ondisk_path, &sb) == -1) {
6649 if (errno(*__errno()) == ENOENT2) {
6650 free(ondisk_path);
6651 continue;
6652 }
6653 error = got_error_from_errno2("lstat",
6654 ondisk_path);
6655 free(ondisk_path);
6656 goto done;
6657 }
6658 free(ondisk_path);
6659 if (S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000)) {
6660 error = got_error_msg(GOT_ERR_BAD_PATH4,
6661 "removing directories requires -R option");
6662 goto done;
6663 }
6664 }
6665 }
6666
6667 error = got_worktree_schedule_delete(worktree, &paths,
6668 delete_local_mods, status_codes, print_remove_status, NULL((void *)0),
6669 repo, keep_on_disk);
6670done:
6671 if (repo)
6672 got_repo_close(repo);
6673 if (worktree)
6674 got_worktree_close(worktree);
6675 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
6676 free((char *)pe->path);
6677 got_pathlist_free(&paths);
6678 free(cwd);
6679 return error;
6680}
6681
6682__dead__attribute__((__noreturn__)) static void
6683usage_revert(void)
6684{
6685 fprintf(stderr(&__sF[2]), "usage: %s revert [-p] [-F response-script] [-R] "
6686 "path ...\n", getprogname());
6687 exit(1);
6688}
6689
6690static const struct got_error *
6691revert_progress(void *arg, unsigned char status, const char *path)
6692{
6693 if (status == GOT_STATUS_UNVERSIONED'?')
6694 return NULL((void *)0);
6695
6696 while (path[0] == '/')
6697 path++;
6698 printf("%c %s\n", status, path);
6699 return NULL((void *)0);
6700}
6701
6702struct choose_patch_arg {
6703 FILE *patch_script_file;
6704 const char *action;
6705};
6706
6707static const struct got_error *
6708show_change(unsigned char status, const char *path, FILE *patch_file, int n,
6709 int nchanges, const char *action)
6710{
6711 char *line = NULL((void *)0);
6712 size_t linesize = 0;
6713 ssize_t linelen;
6714
6715 switch (status) {
6716 case GOT_STATUS_ADD'A':
6717 printf("A %s\n%s this addition? [y/n] ", path, action);
6718 break;
6719 case GOT_STATUS_DELETE'D':
6720 printf("D %s\n%s this deletion? [y/n] ", path, action);
6721 break;
6722 case GOT_STATUS_MODIFY'M':
6723 if (fseek(patch_file, 0L, SEEK_SET0) == -1)
6724 return got_error_from_errno("fseek");
6725 printf(GOT_COMMIT_SEP_STR"-----------------------------------------------\n");
6726 while ((linelen = getline(&line, &linesize, patch_file)) != -1)
6727 printf("%s", line);
6728 if (ferror(patch_file)(!__isthreaded ? (((patch_file)->_flags & 0x0040) != 0
) : (ferror)(patch_file))
)
6729 return got_error_from_errno("getline");
6730 printf(GOT_COMMIT_SEP_STR"-----------------------------------------------\n");
6731 printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
6732 path, n, nchanges, action);
6733 break;
6734 default:
6735 return got_error_path(path, GOT_ERR_FILE_STATUS68);
6736 }
6737
6738 return NULL((void *)0);
6739}
6740
6741static const struct got_error *
6742choose_patch(int *choice, void *arg, unsigned char status, const char *path,
6743 FILE *patch_file, int n, int nchanges)
6744{
6745 const struct got_error *err = NULL((void *)0);
6746 char *line = NULL((void *)0);
6747 size_t linesize = 0;
6748 ssize_t linelen;
6749 int resp = ' ';
6750 struct choose_patch_arg *a = arg;
6751
6752 *choice = GOT_PATCH_CHOICE_NONE0;
6753
6754 if (a->patch_script_file) {
6755 char *nl;
6756 err = show_change(status, path, patch_file, n, nchanges,
6757 a->action);
6758 if (err)
6759 return err;
6760 linelen = getline(&line, &linesize, a->patch_script_file);
6761 if (linelen == -1) {
6762 if (ferror(a->patch_script_file)(!__isthreaded ? (((a->patch_script_file)->_flags &
0x0040) != 0) : (ferror)(a->patch_script_file))
)
6763 return got_error_from_errno("getline");
6764 return NULL((void *)0);
6765 }
6766 nl = strchr(line, '\n');
6767 if (nl)
6768 *nl = '\0';
6769 if (strcmp(line, "y") == 0) {
6770 *choice = GOT_PATCH_CHOICE_YES1;
6771 printf("y\n");
6772 } else if (strcmp(line, "n") == 0) {
6773 *choice = GOT_PATCH_CHOICE_NO2;
6774 printf("n\n");
6775 } else if (strcmp(line, "q") == 0 &&
6776 status == GOT_STATUS_MODIFY'M') {
6777 *choice = GOT_PATCH_CHOICE_QUIT3;
6778 printf("q\n");
6779 } else
6780 printf("invalid response '%s'\n", line);
6781 free(line);
6782 return NULL((void *)0);
6783 }
6784
6785 while (resp != 'y' && resp != 'n' && resp != 'q') {
6786 err = show_change(status, path, patch_file, n, nchanges,
6787 a->action);
6788 if (err)
6789 return err;
6790 resp = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
;
6791 if (resp == '\n')
6792 resp = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
;
6793 if (status == GOT_STATUS_MODIFY'M') {
6794 if (resp != 'y' && resp != 'n' && resp != 'q') {
6795 printf("invalid response '%c'\n", resp);
6796 resp = ' ';
6797 }
6798 } else if (resp != 'y' && resp != 'n') {
6799 printf("invalid response '%c'\n", resp);
6800 resp = ' ';
6801 }
6802 }
6803
6804 if (resp == 'y')
6805 *choice = GOT_PATCH_CHOICE_YES1;
6806 else if (resp == 'n')
6807 *choice = GOT_PATCH_CHOICE_NO2;
6808 else if (resp == 'q' && status == GOT_STATUS_MODIFY'M')
6809 *choice = GOT_PATCH_CHOICE_QUIT3;
6810
6811 return NULL((void *)0);
6812}
6813
6814
6815static const struct got_error *
6816cmd_revert(int argc, char *argv[])
6817{
6818 const struct got_error *error = NULL((void *)0);
6819 struct got_worktree *worktree = NULL((void *)0);
6820 struct got_repository *repo = NULL((void *)0);
6821 char *cwd = NULL((void *)0), *path = NULL((void *)0);
6822 struct got_pathlist_head paths;
6823 struct got_pathlist_entry *pe;
6824 int ch, can_recurse = 0, pflag = 0;
6825 FILE *patch_script_file = NULL((void *)0);
6826 const char *patch_script_path = NULL((void *)0);
6827 struct choose_patch_arg cpa;
6828
6829 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
6830
6831 while ((ch = getopt(argc, argv, "pF:R")) != -1) {
6832 switch (ch) {
6833 case 'p':
6834 pflag = 1;
6835 break;
6836 case 'F':
6837 patch_script_path = optarg;
6838 break;
6839 case 'R':
6840 can_recurse = 1;
6841 break;
6842 default:
6843 usage_revert();
6844 /* NOTREACHED */
6845 }
6846 }
6847
6848 argc -= optind;
6849 argv += optind;
6850
6851#ifndef PROFILE
6852 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
6853 "unveil", NULL((void *)0)) == -1)
6854 err(1, "pledge");
6855#endif
6856 if (argc < 1)
6857 usage_revert();
6858 if (patch_script_path && !pflag)
6859 errx(1, "-F option can only be used together with -p option");
6860
6861 cwd = getcwd(NULL((void *)0), 0);
6862 if (cwd == NULL((void *)0)) {
6863 error = got_error_from_errno("getcwd");
6864 goto done;
6865 }
6866 error = got_worktree_open(&worktree, cwd);
6867 if (error) {
6868 if (error->code == GOT_ERR_NOT_WORKTREE60)
6869 error = wrap_not_worktree_error(error, "revert", cwd);
6870 goto done;
6871 }
6872
6873 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6874 NULL((void *)0));
6875 if (error != NULL((void *)0))
6876 goto done;
6877
6878 if (patch_script_path) {
6879 patch_script_file = fopen(patch_script_path, "r");
6880 if (patch_script_file == NULL((void *)0)) {
6881 error = got_error_from_errno2("fopen",
6882 patch_script_path);
6883 goto done;
6884 }
6885 }
6886 error = apply_unveil(got_repo_get_path(repo), 1,
6887 got_worktree_get_root_path(worktree));
6888 if (error)
6889 goto done;
6890
6891 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6892 if (error)
6893 goto done;
6894
6895 if (!can_recurse) {
6896 char *ondisk_path;
6897 struct stat sb;
6898 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
{
6899 if (asprintf(&ondisk_path, "%s/%s",
6900 got_worktree_get_root_path(worktree),
6901 pe->path) == -1) {
6902 error = got_error_from_errno("asprintf");
6903 goto done;
6904 }
6905 if (lstat(ondisk_path, &sb) == -1) {
6906 if (errno(*__errno()) == ENOENT2) {
6907 free(ondisk_path);
6908 continue;
6909 }
6910 error = got_error_from_errno2("lstat",
6911 ondisk_path);
6912 free(ondisk_path);
6913 goto done;
6914 }
6915 free(ondisk_path);
6916 if (S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000)) {
6917 error = got_error_msg(GOT_ERR_BAD_PATH4,
6918 "reverting directories requires -R option");
6919 goto done;
6920 }
6921 }
6922 }
6923
6924 cpa.patch_script_file = patch_script_file;
6925 cpa.action = "revert";
6926 error = got_worktree_revert(worktree, &paths, revert_progress, NULL((void *)0),
6927 pflag ? choose_patch : NULL((void *)0), &cpa, repo);
6928done:
6929 if (patch_script_file && fclose(patch_script_file) == EOF(-1) &&
6930 error == NULL((void *)0))
6931 error = got_error_from_errno2("fclose", patch_script_path);
6932 if (repo)
6933 got_repo_close(repo);
6934 if (worktree)
6935 got_worktree_close(worktree);
6936 free(path);
6937 free(cwd);
6938 return error;
6939}
6940
6941__dead__attribute__((__noreturn__)) static void
6942usage_commit(void)
6943{
6944 fprintf(stderr(&__sF[2]), "usage: %s commit [-F path] [-m msg] [-N] [-S] "
6945 "[path ...]\n", getprogname());
6946 exit(1);
6947}
6948
6949struct collect_commit_logmsg_arg {
6950 const char *cmdline_log;
6951 const char *prepared_log;
6952 int non_interactive;
6953 const char *editor;
6954 const char *worktree_path;
6955 const char *branch_name;
6956 const char *repo_path;
6957 char *logmsg_path;
6958
6959};
6960
6961static const struct got_error *
6962read_prepared_logmsg(char **logmsg, const char *path)
6963{
6964 const struct got_error *err = NULL((void *)0);
6965 FILE *f = NULL((void *)0);
6966 struct stat sb;
6967 size_t r;
6968
6969 *logmsg = NULL((void *)0);
6970 memset(&sb, 0, sizeof(sb));
6971
6972 f = fopen(path, "r");
6973 if (f == NULL((void *)0))
6974 return got_error_from_errno2("fopen", path);
6975
6976 if (fstat(fileno(f)(!__isthreaded ? ((f)->_file) : (fileno)(f)), &sb) == -1) {
6977 err = got_error_from_errno2("fstat", path);
6978 goto done;
6979 }
6980 if (sb.st_size == 0) {
6981 err = got_error(GOT_ERR_COMMIT_MSG_EMPTY74);
6982 goto done;
6983 }
6984
6985 *logmsg = malloc(sb.st_size + 1);
6986 if (*logmsg == NULL((void *)0)) {
6987 err = got_error_from_errno("malloc");
6988 goto done;
6989 }
6990
6991 r = fread(*logmsg, 1, sb.st_size, f);
6992 if (r != sb.st_size) {
6993 if (ferror(f)(!__isthreaded ? (((f)->_flags & 0x0040) != 0) : (ferror
)(f))
)
6994 err = got_error_from_errno2("fread", path);
6995 else
6996 err = got_error(GOT_ERR_IO6);
6997 goto done;
6998 }
6999 (*logmsg)[sb.st_size] = '\0';
7000done:
7001 if (fclose(f) == EOF(-1) && err == NULL((void *)0))
7002 err = got_error_from_errno2("fclose", path);
7003 if (err) {
7004 free(*logmsg);
7005 *logmsg = NULL((void *)0);
7006 }
7007 return err;
7008
7009}
7010
7011static const struct got_error *
7012collect_commit_logmsg(struct got_pathlist_head *commitable_paths, char **logmsg,
7013 void *arg)
7014{
7015 char *initial_content = NULL((void *)0);
7016 struct got_pathlist_entry *pe;
7017 const struct got_error *err = NULL((void *)0);
7018 char *template = NULL((void *)0);
7019 struct collect_commit_logmsg_arg *a = arg;
7020 int initial_content_len;
7021 int fd = -1;
7022 size_t len;
7023
7024 /* if a message was specified on the command line, just use it */
7025 if (a->cmdline_log != NULL((void *)0) && strlen(a->cmdline_log) != 0) {
7026 len = strlen(a->cmdline_log) + 1;
7027 *logmsg = malloc(len + 1);
7028 if (*logmsg == NULL((void *)0))
7029 return got_error_from_errno("malloc");
7030 strlcpy(*logmsg, a->cmdline_log, len);
7031 return NULL((void *)0);
7032 } else if (a->prepared_log != NULL((void *)0) && a->non_interactive)
7033 return read_prepared_logmsg(logmsg, a->prepared_log);
7034
7035 if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1)
7036 return got_error_from_errno("asprintf");
7037
7038 err = got_opentemp_named_fd(&a->logmsg_path, &fd, template);
7039 if (err)
7040 goto done;
7041
7042 if (a->prepared_log) {
7043 char *msg;
7044 err = read_prepared_logmsg(&msg, a->prepared_log);
7045 if (err)
7046 goto done;
7047 if (write(fd, msg, strlen(msg)) == -1) {
7048 err = got_error_from_errno2("write", a->logmsg_path);
7049 free(msg);
7050 goto done;
7051 }
7052 free(msg);
7053 }
7054
7055 initial_content_len = asprintf(&initial_content,
7056 "\n# changes to be committed on branch %s:\n",
7057 a->branch_name);
7058 if (initial_content_len == -1) {
7059 err = got_error_from_errno("asprintf");
7060 goto done;
7061 }
7062
7063 if (write(fd, initial_content, initial_content_len) == -1) {
7064 err = got_error_from_errno2("write", a->logmsg_path);
7065 goto done;
7066 }
7067
7068 TAILQ_FOREACH(pe, commitable_paths, entry)for((pe) = ((commitable_paths)->tqh_first); (pe) != ((void
*)0); (pe) = ((pe)->entry.tqe_next))
{
7069 struct got_commitable *ct = pe->data;
7070 dprintf(fd, "# %c %s\n",
7071 got_commitable_get_status(ct),
7072 got_commitable_get_path(ct));
7073 }
7074
7075 err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content,
7076 initial_content_len, a->prepared_log ? 0 : 1);
7077done:
7078 free(initial_content);
7079 free(template);
7080
7081 if (fd != -1 && close(fd) == -1 && err == NULL((void *)0))
7082 err = got_error_from_errno2("close", a->logmsg_path);
7083
7084 /* Editor is done; we can now apply unveil(2) */
7085 if (err == NULL((void *)0))
7086 err = apply_unveil(a->repo_path, 0, a->worktree_path);
7087 if (err) {
7088 free(*logmsg);
7089 *logmsg = NULL((void *)0);
7090 }
7091 return err;
7092}
7093
7094static const struct got_error *
7095cmd_commit(int argc, char *argv[])
7096{
7097 const struct got_error *error = NULL((void *)0);
7098 struct got_worktree *worktree = NULL((void *)0);
7099 struct got_repository *repo = NULL((void *)0);
7100 char *cwd = NULL((void *)0), *id_str = NULL((void *)0);
7101 struct got_object_id *id = NULL((void *)0);
7102 const char *logmsg = NULL((void *)0);
7103 char *prepared_logmsg = NULL((void *)0);
7104 struct collect_commit_logmsg_arg cl_arg;
7105 char *gitconfig_path = NULL((void *)0), *editor = NULL((void *)0), *author = NULL((void *)0);
7106 int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0;
7107 int allow_bad_symlinks = 0, non_interactive = 0;
7108 struct got_pathlist_head paths;
7109
7110 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
7111 cl_arg.logmsg_path = NULL((void *)0);
7112
7113 while ((ch = getopt(argc, argv, "F:m:NS")) != -1) {
7114 switch (ch) {
7115 case 'F':
7116 if (logmsg != NULL((void *)0))
7117 option_conflict('F', 'm');
7118 prepared_logmsg = realpath(optarg, NULL((void *)0));
7119 if (prepared_logmsg == NULL((void *)0))
7120 return got_error_from_errno2("realpath",
7121 optarg);
7122 break;
7123 case 'm':
7124 if (prepared_logmsg)
7125 option_conflict('m', 'F');
7126 logmsg = optarg;
7127 break;
7128 case 'N':
7129 non_interactive = 1;
7130 break;
7131 case 'S':
7132 allow_bad_symlinks = 1;
7133 break;
7134 default:
7135 usage_commit();
7136 /* NOTREACHED */
7137 }
7138 }
7139
7140 argc -= optind;
7141 argv += optind;
7142
7143#ifndef PROFILE
7144 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7145 "unveil", NULL((void *)0)) == -1)
7146 err(1, "pledge");
7147#endif
7148 cwd = getcwd(NULL((void *)0), 0);
7149 if (cwd == NULL((void *)0)) {
7150 error = got_error_from_errno("getcwd");
7151 goto done;
7152 }
7153 error = got_worktree_open(&worktree, cwd);
7154 if (error) {
7155 if (error->code == GOT_ERR_NOT_WORKTREE60)
7156 error = wrap_not_worktree_error(error, "commit", cwd);
7157 goto done;
7158 }
7159
7160 error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
7161 if (error)
7162 goto done;
7163 if (rebase_in_progress) {
7164 error = got_error(GOT_ERR_REBASING88);
7165 goto done;
7166 }
7167
7168 error = got_worktree_histedit_in_progress(&histedit_in_progress,
7169 worktree);
7170 if (error)
7171 goto done;
7172
7173 error = get_gitconfig_path(&gitconfig_path);
7174 if (error)
7175 goto done;
7176 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7177 gitconfig_path);
7178 if (error != NULL((void *)0))
7179 goto done;
7180
7181 error = get_author(&author, repo, worktree);
7182 if (error)
7183 return error;
7184
7185 /*
7186 * unveil(2) traverses exec(2); if an editor is used we have
7187 * to apply unveil after the log message has been written.
7188 */
7189 if (logmsg == NULL((void *)0) || strlen(logmsg) == 0)
7190 error = get_editor(&editor);
7191 else
7192 error = apply_unveil(got_repo_get_path(repo), 0,
7193 got_worktree_get_root_path(worktree));
7194 if (error)
7195 goto done;
7196
7197 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7198 if (error)
7199 goto done;
7200
7201 cl_arg.editor = editor;
7202 cl_arg.cmdline_log = logmsg;
7203 cl_arg.prepared_log = prepared_logmsg;
7204 cl_arg.non_interactive = non_interactive;
7205 cl_arg.worktree_path = got_worktree_get_root_path(worktree);
7206 cl_arg.branch_name = got_worktree_get_head_ref_name(worktree);
7207 if (!histedit_in_progress) {
7208 if (strncmp(cl_arg.branch_name, "refs/heads/", 11) != 0) {
7209 error = got_error(GOT_ERR_COMMIT_BRANCH100);
7210 goto done;
7211 }
7212 cl_arg.branch_name += 11;
7213 }
7214 cl_arg.repo_path = got_repo_get_path(repo);
7215 error = got_worktree_commit(&id, worktree, &paths, author, NULL((void *)0),
7216 allow_bad_symlinks, collect_commit_logmsg, &cl_arg,
7217 print_status, NULL((void *)0), repo);
7218 if (error) {
7219 if (error->code != GOT_ERR_COMMIT_MSG_EMPTY74 &&
7220 cl_arg.logmsg_path != NULL((void *)0))
7221 preserve_logmsg = 1;
7222 goto done;
7223 }
7224
7225 error = got_object_id_str(&id_str, id);
7226 if (error)
7227 goto done;
7228 printf("Created commit %s\n", id_str);
7229done:
7230 if (preserve_logmsg) {
7231 fprintf(stderr(&__sF[2]), "%s: log message preserved in %s\n",
7232 getprogname(), cl_arg.logmsg_path);
7233 } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 &&
7234 error == NULL((void *)0))
7235 error = got_error_from_errno2("unlink", cl_arg.logmsg_path);
7236 free(cl_arg.logmsg_path);
7237 if (repo)
7238 got_repo_close(repo);
7239 if (worktree)
7240 got_worktree_close(worktree);
7241 free(cwd);
7242 free(id_str);
7243 free(gitconfig_path);
7244 free(editor);
7245 free(author);
7246 free(prepared_logmsg);
7247 return error;
7248}
7249
7250__dead__attribute__((__noreturn__)) static void
7251usage_cherrypick(void)
7252{
7253 fprintf(stderr(&__sF[2]), "usage: %s cherrypick commit-id\n", getprogname());
7254 exit(1);
7255}
7256
7257static const struct got_error *
7258cmd_cherrypick(int argc, char *argv[])
7259{
7260 const struct got_error *error = NULL((void *)0);
7261 struct got_worktree *worktree = NULL((void *)0);
7262 struct got_repository *repo = NULL((void *)0);
7263 char *cwd = NULL((void *)0), *commit_id_str = NULL((void *)0);
7264 struct got_object_id *commit_id = NULL((void *)0);
7265 struct got_commit_object *commit = NULL((void *)0);
7266 struct got_object_qid *pid;
7267 struct got_reference *head_ref = NULL((void *)0);
7268 int ch;
7269 struct got_update_progress_arg upa;
7270
7271 while ((ch = getopt(argc, argv, "")) != -1) {
7272 switch (ch) {
7273 default:
7274 usage_cherrypick();
7275 /* NOTREACHED */
7276 }
7277 }
7278
7279 argc -= optind;
7280 argv += optind;
7281
7282#ifndef PROFILE
7283 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7284 "unveil", NULL((void *)0)) == -1)
7285 err(1, "pledge");
7286#endif
7287 if (argc != 1)
7288 usage_cherrypick();
7289
7290 cwd = getcwd(NULL((void *)0), 0);
7291 if (cwd == NULL((void *)0)) {
7292 error = got_error_from_errno("getcwd");
7293 goto done;
7294 }
7295 error = got_worktree_open(&worktree, cwd);
7296 if (error) {
7297 if (error->code == GOT_ERR_NOT_WORKTREE60)
7298 error = wrap_not_worktree_error(error, "cherrypick",
7299 cwd);
7300 goto done;
7301 }
7302
7303 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7304 NULL((void *)0));
7305 if (error != NULL((void *)0))
7306 goto done;
7307
7308 error = apply_unveil(got_repo_get_path(repo), 0,
7309 got_worktree_get_root_path(worktree));
7310 if (error)
7311 goto done;
7312
7313 error = got_repo_match_object_id_prefix(&commit_id, argv[0],
7314 GOT_OBJ_TYPE_COMMIT1, repo);
7315 if (error != NULL((void *)0)) {
7316 struct got_reference *ref;
7317 if (error->code != GOT_ERR_BAD_OBJ_ID_STR23)
7318 goto done;
7319 error = got_ref_open(&ref, repo, argv[0], 0);
7320 if (error != NULL((void *)0))
7321 goto done;
7322 error = got_ref_resolve(&commit_id, repo, ref);
7323 got_ref_close(ref);
7324 if (error != NULL((void *)0))
7325 goto done;
7326 }
7327 error = got_object_id_str(&commit_id_str, commit_id);
7328 if (error)
7329 goto done;
7330
7331 error = got_ref_open(&head_ref, repo,
7332 got_worktree_get_head_ref_name(worktree), 0);
7333 if (error != NULL((void *)0))
7334 goto done;
7335
7336 error = check_same_branch(commit_id, head_ref, NULL((void *)0), repo);
7337 if (error) {
7338 if (error->code != GOT_ERR_ANCESTRY55)
7339 goto done;
7340 error = NULL((void *)0);
7341 } else {
7342 error = got_error(GOT_ERR_SAME_BRANCH79);
7343 goto done;
7344 }
7345
7346 error = got_object_open_as_commit(&commit, repo, commit_id);
7347 if (error)
7348 goto done;
7349 pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit))((got_object_commit_get_parent_ids(commit))->sqh_first);
7350 memset(&upa, 0, sizeof(upa));
7351 error = got_worktree_merge_files(worktree, pid ? pid->id : NULL((void *)0),
7352 commit_id, repo, update_progress, &upa, check_cancelled,
7353 NULL((void *)0));
7354 if (error != NULL((void *)0))
7355 goto done;
7356
7357 if (upa.did_something)
7358 printf("Merged commit %s\n", commit_id_str);
7359 print_update_progress_stats(&upa);
7360done:
7361 if (commit)
7362 got_object_commit_close(commit);
7363 free(commit_id_str);
7364 if (head_ref)
7365 got_ref_close(head_ref);
7366 if (worktree)
7367 got_worktree_close(worktree);
7368 if (repo)
7369 got_repo_close(repo);
7370 return error;
7371}
7372
7373__dead__attribute__((__noreturn__)) static void
7374usage_backout(void)
7375{
7376 fprintf(stderr(&__sF[2]), "usage: %s backout commit-id\n", getprogname());
7377 exit(1);
7378}
7379
7380static const struct got_error *
7381cmd_backout(int argc, char *argv[])
7382{
7383 const struct got_error *error = NULL((void *)0);
7384 struct got_worktree *worktree = NULL((void *)0);
7385 struct got_repository *repo = NULL((void *)0);
7386 char *cwd = NULL((void *)0), *commit_id_str = NULL((void *)0);
7387 struct got_object_id *commit_id = NULL((void *)0);
7388 struct got_commit_object *commit = NULL((void *)0);
7389 struct got_object_qid *pid;
7390 struct got_reference *head_ref = NULL((void *)0);
7391 int ch;
7392 struct got_update_progress_arg upa;
7393
7394 while ((ch = getopt(argc, argv, "")) != -1) {
7395 switch (ch) {
7396 default:
7397 usage_backout();
7398 /* NOTREACHED */
7399 }
7400 }
7401
7402 argc -= optind;
7403 argv += optind;
7404
7405#ifndef PROFILE
7406 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7407 "unveil", NULL((void *)0)) == -1)
7408 err(1, "pledge");
7409#endif
7410 if (argc != 1)
7411 usage_backout();
7412
7413 cwd = getcwd(NULL((void *)0), 0);
7414 if (cwd == NULL((void *)0)) {
7415 error = got_error_from_errno("getcwd");
7416 goto done;
7417 }
7418 error = got_worktree_open(&worktree, cwd);
7419 if (error) {
7420 if (error->code == GOT_ERR_NOT_WORKTREE60)
7421 error = wrap_not_worktree_error(error, "backout", cwd);
7422 goto done;
7423 }
7424
7425 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7426 NULL((void *)0));
7427 if (error != NULL((void *)0))
7428 goto done;
7429
7430 error = apply_unveil(got_repo_get_path(repo), 0,
7431 got_worktree_get_root_path(worktree));
7432 if (error)
7433 goto done;
7434
7435 error = got_repo_match_object_id_prefix(&commit_id, argv[0],
7436 GOT_OBJ_TYPE_COMMIT1, repo);
7437 if (error != NULL((void *)0)) {
7438 struct got_reference *ref;
7439 if (error->code != GOT_ERR_BAD_OBJ_ID_STR23)
7440 goto done;
7441 error = got_ref_open(&ref, repo, argv[0], 0);
7442 if (error != NULL((void *)0))
7443 goto done;
7444 error = got_ref_resolve(&commit_id, repo, ref);
7445 got_ref_close(ref);
7446 if (error != NULL((void *)0))
7447 goto done;
7448 }
7449 error = got_object_id_str(&commit_id_str, commit_id);
7450 if (error)
7451 goto done;
7452
7453 error = got_ref_open(&head_ref, repo,
7454 got_worktree_get_head_ref_name(worktree), 0);
7455 if (error != NULL((void *)0))
7456 goto done;
7457
7458 error = check_same_branch(commit_id, head_ref, NULL((void *)0), repo);
7459 if (error)
7460 goto done;
7461
7462 error = got_object_open_as_commit(&commit, repo, commit_id);
7463 if (error)
7464 goto done;
7465 pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit))((got_object_commit_get_parent_ids(commit))->sqh_first);
7466 if (pid == NULL((void *)0)) {
7467 error = got_error(GOT_ERR_ROOT_COMMIT80);
7468 goto done;
7469 }
7470
7471 memset(&upa, 0, sizeof(upa));
7472 error = got_worktree_merge_files(worktree, commit_id, pid->id, repo,
7473 update_progress, &upa, check_cancelled, NULL((void *)0));
7474 if (error != NULL((void *)0))
7475 goto done;
7476
7477 if (upa.did_something)
7478 printf("Backed out commit %s\n", commit_id_str);
7479 print_update_progress_stats(&upa);
7480done:
7481 if (commit)
7482 got_object_commit_close(commit);
7483 free(commit_id_str);
7484 if (head_ref)
7485 got_ref_close(head_ref);
7486 if (worktree)
7487 got_worktree_close(worktree);
7488 if (repo)
7489 got_repo_close(repo);
7490 return error;
7491}
7492
7493__dead__attribute__((__noreturn__)) static void
7494usage_rebase(void)
7495{
7496 fprintf(stderr(&__sF[2]), "usage: %s rebase [-a] [-c] [-l] [branch]\n",
7497 getprogname());
7498 exit(1);
7499}
7500
7501void
7502trim_logmsg(char *logmsg, int limit)
7503{
7504 char *nl;
7505 size_t len;
7506
7507 len = strlen(logmsg);
7508 if (len > limit)
7509 len = limit;
7510 logmsg[len] = '\0';
7511 nl = strchr(logmsg, '\n');
7512 if (nl)
7513 *nl = '\0';
7514}
7515
7516static const struct got_error *
7517get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit)
7518{
7519 const struct got_error *err;
7520 char *logmsg0 = NULL((void *)0);
7521 const char *s;
7522
7523 err = got_object_commit_get_logmsg(&logmsg0, commit);
7524 if (err)
7525 return err;
7526
7527 s = logmsg0;
7528 while (isspace((unsigned char)s[0]))
7529 s++;
7530
7531 *logmsg = strdup(s);
7532 if (*logmsg == NULL((void *)0)) {
7533 err = got_error_from_errno("strdup");
7534 goto done;
7535 }
7536
7537 trim_logmsg(*logmsg, limit);
7538done:
7539 free(logmsg0);
7540 return err;
7541}
7542
7543static const struct got_error *
7544show_rebase_merge_conflict(struct got_object_id *id, struct got_repository *repo)
7545{
7546 const struct got_error *err;
7547 struct got_commit_object *commit = NULL((void *)0);
7548 char *id_str = NULL((void *)0), *logmsg = NULL((void *)0);
7549
7550 err = got_object_open_as_commit(&commit, repo, id);
7551 if (err)
7552 return err;
7553
7554 err = got_object_id_str(&id_str, id);
7555 if (err)
7556 goto done;
7557
7558 id_str[12] = '\0';
7559
7560 err = get_short_logmsg(&logmsg, 42, commit);
7561 if (err)
7562 goto done;
7563
7564 printf("%s -> merge conflict: %s\n", id_str, logmsg);
7565done:
7566 free(id_str);
7567 got_object_commit_close(commit);
7568 free(logmsg);
7569 return err;
7570}
7571
7572static const struct got_error *
7573show_rebase_progress(struct got_commit_object *commit,
7574 struct got_object_id *old_id, struct got_object_id *new_id)
7575{
7576 const struct got_error *err;
7577 char *old_id_str = NULL((void *)0), *new_id_str = NULL((void *)0), *logmsg = NULL((void *)0);
7578
7579 err = got_object_id_str(&old_id_str, old_id);
7580 if (err)
7581 goto done;
7582
7583 if (new_id) {
7584 err = got_object_id_str(&new_id_str, new_id);
7585 if (err)
7586 goto done;
7587 }
7588
7589 old_id_str[12] = '\0';
7590 if (new_id_str)
7591 new_id_str[12] = '\0';
7592
7593 err = get_short_logmsg(&logmsg, 42, commit);
7594 if (err)
7595 goto done;
7596
7597 printf("%s -> %s: %s\n", old_id_str,
7598 new_id_str ? new_id_str : "no-op change", logmsg);
7599done:
7600 free(old_id_str);
7601 free(new_id_str);
7602 free(logmsg);
7603 return err;
7604}
7605
7606static const struct got_error *
7607rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex,
7608 struct got_reference *branch, struct got_reference *new_base_branch,
7609 struct got_reference *tmp_branch, struct got_repository *repo,
7610 int create_backup)
7611{
7612 printf("Switching work tree to %s\n", got_ref_get_name(branch));
7613 return got_worktree_rebase_complete(worktree, fileindex,
7614 new_base_branch, tmp_branch, branch, repo, create_backup);
7615}
7616
7617static const struct got_error *
7618rebase_commit(struct got_pathlist_head *merged_paths,
7619 struct got_worktree *worktree, struct got_fileindex *fileindex,
7620 struct got_reference *tmp_branch,
7621 struct got_object_id *commit_id, struct got_repository *repo)
7622{
7623 const struct got_error *error;
7624 struct got_commit_object *commit;
7625 struct got_object_id *new_commit_id;
7626
7627 error = got_object_open_as_commit(&commit, repo, commit_id);
7628 if (error)
7629 return error;
7630
7631 error = got_worktree_rebase_commit(&new_commit_id, merged_paths,
7632 worktree, fileindex, tmp_branch, commit, commit_id, repo);
7633 if (error) {
7634 if (error->code != GOT_ERR_COMMIT_NO_CHANGES76)
7635 goto done;
7636 error = show_rebase_progress(commit, commit_id, NULL((void *)0));
7637 } else {
7638 error = show_rebase_progress(commit, commit_id, new_commit_id);
7639 free(new_commit_id);
7640 }
7641done:
7642 got_object_commit_close(commit);
7643 return error;
7644}
7645
7646struct check_path_prefix_arg {
7647 const char *path_prefix;
7648 size_t len;
7649 int errcode;
7650};
7651
7652static const struct got_error *
7653check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1,
7654 struct got_blob_object *blob2, struct got_object_id *id1,
7655 struct got_object_id *id2, const char *path1, const char *path2,
7656 mode_t mode1, mode_t mode2, struct got_repository *repo)
7657{
7658 struct check_path_prefix_arg *a = arg;
7659
7660 if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
7661 (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
7662 return got_error(a->errcode);
7663
7664 return NULL((void *)0);
7665}
7666
7667static const struct got_error *
7668check_path_prefix(struct got_object_id *parent_id,
7669 struct got_object_id *commit_id, const char *path_prefix,
7670 int errcode, struct got_repository *repo)
7671{
7672 const struct got_error *err;
7673 struct got_tree_object *tree1 = NULL((void *)0), *tree2 = NULL((void *)0);
7674 struct got_commit_object *commit = NULL((void *)0), *parent_commit = NULL((void *)0);
7675 struct check_path_prefix_arg cpp_arg;
7676
7677 if (got_path_is_root_dir(path_prefix))
7678 return NULL((void *)0);
7679
7680 err = got_object_open_as_commit(&commit, repo, commit_id);
7681 if (err)
7682 goto done;
7683
7684 err = got_object_open_as_commit(&parent_commit, repo, parent_id);
7685 if (err)
7686 goto done;
7687
7688 err = got_object_open_as_tree(&tree1, repo,
7689 got_object_commit_get_tree_id(parent_commit));
7690 if (err)
7691 goto done;
7692
7693 err = got_object_open_as_tree(&tree2, repo,
7694 got_object_commit_get_tree_id(commit));
7695 if (err)
7696 goto done;
7697
7698 cpp_arg.path_prefix = path_prefix;
7699 while (cpp_arg.path_prefix[0] == '/')
7700 cpp_arg.path_prefix++;
7701 cpp_arg.len = strlen(cpp_arg.path_prefix);
7702 cpp_arg.errcode = errcode;
7703 err = got_diff_tree(tree1, tree2, "", "", repo,
7704 check_path_prefix_in_diff, &cpp_arg, 0);
7705done:
7706 if (tree1)
7707 got_object_tree_close(tree1);
7708 if (tree2)
7709 got_object_tree_close(tree2);
7710 if (commit)
7711 got_object_commit_close(commit);
7712 if (parent_commit)
7713 got_object_commit_close(parent_commit);
7714 return err;
7715}
7716
7717static const struct got_error *
7718collect_commits(struct got_object_id_queue *commits,
7719 struct got_object_id *initial_commit_id,
7720 struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id,
7721 const char *path_prefix, int path_prefix_errcode,
7722 struct got_repository *repo)
7723{
7724 const struct got_error *err = NULL((void *)0);
7725 struct got_commit_graph *graph = NULL((void *)0);
7726 struct got_object_id *parent_id = NULL((void *)0);
7727 struct got_object_qid *qid;
7728 struct got_object_id *commit_id = initial_commit_id;
7729
7730 err = got_commit_graph_open(&graph, "/", 1);
7731 if (err)
7732 return err;
7733
7734 err = got_commit_graph_iter_start(graph, iter_start_id, repo,
7735 check_cancelled, NULL((void *)0));
7736 if (err)
7737 goto done;
7738 while (got_object_id_cmp(commit_id, iter_stop_id) != 0) {
7739 err = got_commit_graph_iter_next(&parent_id, graph, repo,
7740 check_cancelled, NULL((void *)0));
7741 if (err) {
7742 if (err->code == GOT_ERR_ITER_COMPLETED46) {
7743 err = got_error_msg(GOT_ERR_ANCESTRY55,
7744 "ran out of commits to rebase before "
7745 "youngest common ancestor commit has "
7746 "been reached?!?");
7747 }
7748 goto done;
7749 } else {
7750 err = check_path_prefix(parent_id, commit_id,
7751 path_prefix, path_prefix_errcode, repo);
7752 if (err)
7753 goto done;
7754
7755 err = got_object_qid_alloc(&qid, commit_id);
7756 if (err)
7757 goto done;
7758 SIMPLEQ_INSERT_HEAD(commits, qid, entry)do { if (((qid)->entry.sqe_next = (commits)->sqh_first)
== ((void *)0)) (commits)->sqh_last = &(qid)->entry
.sqe_next; (commits)->sqh_first = (qid); } while (0)
;
7759 commit_id = parent_id;
7760 }
7761 }
7762done:
7763 got_commit_graph_close(graph);
7764 return err;
7765}
7766
7767static const struct got_error *
7768get_commit_brief_str(char **brief_str, struct got_commit_object *commit)
7769{
7770 const struct got_error *err = NULL((void *)0);
7771 time_t committer_time;
7772 struct tm tm;
7773 char datebuf[11]; /* YYYY-MM-DD + NUL */
7774 char *author0 = NULL((void *)0), *author, *smallerthan;
7775 char *logmsg0 = NULL((void *)0), *logmsg, *newline;
7776
7777 committer_time = got_object_commit_get_committer_time(commit);
7778 if (localtime_r(&committer_time, &tm) == NULL((void *)0))
7779 return got_error_from_errno("localtime_r");
7780 if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d", &tm) == 0)
7781 return got_error(GOT_ERR_NO_SPACE9);
7782
7783 author0 = strdup(got_object_commit_get_author(commit));
7784 if (author0 == NULL((void *)0))
7785 return got_error_from_errno("strdup");
7786 author = author0;
7787 smallerthan = strchr(author, '<');
7788 if (smallerthan && smallerthan[1] != '\0')
7789 author = smallerthan + 1;
7790 author[strcspn(author, "@>")] = '\0';
7791
7792 err = got_object_commit_get_logmsg(&logmsg0, commit);
7793 if (err)
7794 goto done;
7795 logmsg = logmsg0;
7796 while (*logmsg == '\n')
7797 logmsg++;
7798 newline = strchr(logmsg, '\n');
7799 if (newline)
7800 *newline = '\0';
7801
7802 if (asprintf(brief_str, "%s %s %s",
7803 datebuf, author, logmsg) == -1)
7804 err = got_error_from_errno("asprintf");
7805done:
7806 free(author0);
7807 free(logmsg0);
7808 return err;
7809}
7810
7811static const struct got_error *
7812print_backup_ref(const char *branch_name, const char *new_id_str,
7813 struct got_object_id *old_commit_id, struct got_commit_object *old_commit,
7814 struct got_reflist_object_id_map *refs_idmap,
7815 struct got_repository *repo)
7816{
7817 const struct got_error *err = NULL((void *)0);
7818 struct got_reflist_head *refs;
7819 char *refs_str = NULL((void *)0);
7820 struct got_object_id *new_commit_id = NULL((void *)0);
7821 struct got_commit_object *new_commit = NULL((void *)0);
7822 char *new_commit_brief_str = NULL((void *)0);
7823 struct got_object_id *yca_id = NULL((void *)0);
7824 struct got_commit_object *yca_commit = NULL((void *)0);
7825 char *yca_id_str = NULL((void *)0), *yca_brief_str = NULL((void *)0);
7826 char *custom_refs_str;
7827
7828 if (asprintf(&custom_refs_str, "formerly %s", branch_name) == -1)
7829 return got_error_from_errno("asprintf");
7830
7831 err = print_commit(old_commit, old_commit_id, repo, NULL((void *)0), NULL((void *)0),
7832 0, 0, refs_idmap, custom_refs_str);
7833 if (err)
7834 goto done;
7835
7836 err = got_object_resolve_id_str(&new_commit_id, repo, new_id_str);
7837 if (err)
7838 goto done;
7839
7840 refs = got_reflist_object_id_map_lookup(refs_idmap, new_commit_id);
7841 if (refs) {
7842 err = build_refs_str(&refs_str, refs, new_commit_id, repo);
7843 if (err)
7844 goto done;
7845 }
7846
7847 err = got_object_open_as_commit(&new_commit, repo, new_commit_id);
7848 if (err)
7849 goto done;
7850
7851 err = get_commit_brief_str(&new_commit_brief_str, new_commit);
7852 if (err)
7853 goto done;
7854
7855 err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
7856 old_commit_id, new_commit_id, repo, check_cancelled, NULL((void *)0));
7857 if (err)
7858 goto done;
7859
7860 printf("has become commit %s%s%s%s\n %s\n", new_id_str,
7861 refs_str ? " (" : "", refs_str ? refs_str : "",
7862 refs_str ? ")" : "", new_commit_brief_str);
7863 if (yca_id && got_object_id_cmp(yca_id, new_commit_id) != 0 &&
7864 got_object_id_cmp(yca_id, old_commit_id) != 0) {
7865 free(refs_str);
7866 refs_str = NULL((void *)0);
7867
7868 err = got_object_open_as_commit(&yca_commit, repo, yca_id);
7869 if (err)
7870 goto done;
7871
7872 err = get_commit_brief_str(&yca_brief_str, yca_commit);
7873 if (err)
7874 goto done;
7875
7876 err = got_object_id_str(&yca_id_str, yca_id);
7877 if (err)
7878 goto done;
7879
7880 refs = got_reflist_object_id_map_lookup(refs_idmap, yca_id);
7881 if (refs) {
7882 err = build_refs_str(&refs_str, refs, yca_id, repo);
7883 if (err)
7884 goto done;
7885 }
7886 printf("history forked at %s%s%s%s\n %s\n",
7887 yca_id_str,
7888 refs_str ? " (" : "", refs_str ? refs_str : "",
7889 refs_str ? ")" : "", yca_brief_str);
7890 }
7891done:
7892 free(custom_refs_str);
7893 free(new_commit_id);
7894 free(refs_str);
7895 free(yca_id);
7896 free(yca_id_str);
7897 free(yca_brief_str);
7898 if (new_commit)
7899 got_object_commit_close(new_commit);
7900 if (yca_commit)
7901 got_object_commit_close(yca_commit);
7902
7903 return NULL((void *)0);
7904}
7905
7906static const struct got_error *
7907list_backup_refs(const char *backup_ref_prefix, const char *wanted_branch_name,
7908 struct got_repository *repo)
7909{
7910 const struct got_error *err;
7911 struct got_reflist_head refs, backup_refs;
7912 struct got_reflist_entry *re;
7913 const size_t backup_ref_prefix_len = strlen(backup_ref_prefix);
7914 struct got_object_id *old_commit_id = NULL((void *)0);
7915 char *branch_name = NULL((void *)0);
7916 struct got_commit_object *old_commit = NULL((void *)0);
7917 struct got_reflist_object_id_map *refs_idmap = NULL((void *)0);
7918 int wanted_branch_found = 0;
7919
7920 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
7921 TAILQ_INIT(&backup_refs)do { (&backup_refs)->tqh_first = ((void *)0); (&backup_refs
)->tqh_last = &(&backup_refs)->tqh_first; } while
(0)
;
7922
7923 err = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name, NULL((void *)0));
7924 if (err)
7925 return err;
7926
7927 err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
7928 if (err)
7929 goto done;
7930
7931 if (wanted_branch_name) {
7932 if (strncmp(wanted_branch_name, "refs/heads/", 11) == 0)
7933 wanted_branch_name += 11;
7934 }
7935
7936 err = got_ref_list(&backup_refs, repo, backup_ref_prefix,
7937 got_ref_cmp_by_commit_timestamp_descending, repo);
7938 if (err)
7939 goto done;
7940
7941 TAILQ_FOREACH(re, &backup_refs, entry)for((re) = ((&backup_refs)->tqh_first); (re) != ((void
*)0); (re) = ((re)->entry.tqe_next))
{
7942 const char *refname = got_ref_get_name(re->ref);
7943 char *slash;
7944
7945 err = got_ref_resolve(&old_commit_id, repo, re->ref);
7946 if (err)
7947 break;
7948
7949 err = got_object_open_as_commit(&old_commit, repo,
7950 old_commit_id);
7951 if (err)
7952 break;
7953
7954 if (strncmp(backup_ref_prefix, refname,
7955 backup_ref_prefix_len) == 0)
7956 refname += backup_ref_prefix_len;
7957
7958 while (refname[0] == '/')
7959 refname++;
7960
7961 branch_name = strdup(refname);
7962 if (branch_name == NULL((void *)0)) {
7963 err = got_error_from_errno("strdup");
7964 break;
7965 }
7966 slash = strrchr(branch_name, '/');
7967 if (slash) {
7968 *slash = '\0';
7969 refname += strlen(branch_name) + 1;
7970 }
7971
7972 if (wanted_branch_name == NULL((void *)0) ||
7973 strcmp(wanted_branch_name, branch_name) == 0) {
7974 wanted_branch_found = 1;
7975 err = print_backup_ref(branch_name, refname,
7976 old_commit_id, old_commit, refs_idmap, repo);
7977 if (err)
7978 break;
7979 }
7980
7981 free(old_commit_id);
7982 old_commit_id = NULL((void *)0);
7983 free(branch_name);
7984 branch_name = NULL((void *)0);
7985 got_object_commit_close(old_commit);
7986 old_commit = NULL((void *)0);
7987 }
7988
7989 if (wanted_branch_name && !wanted_branch_found) {
7990 err = got_error_fmt(GOT_ERR_NOT_REF5,
7991 "%s/%s/", backup_ref_prefix, wanted_branch_name);
7992 }
7993done:
7994 if (refs_idmap)
7995 got_reflist_object_id_map_free(refs_idmap);
7996 got_ref_list_free(&refs);
7997 got_ref_list_free(&backup_refs);
7998 free(old_commit_id);
7999 free(branch_name);
8000 if (old_commit)
8001 got_object_commit_close(old_commit);
8002 return err;
8003}
8004
8005static const struct got_error *
8006cmd_rebase(int argc, char *argv[])
8007{
8008 const struct got_error *error = NULL((void *)0);
8009 struct got_worktree *worktree = NULL((void *)0);
8010 struct got_repository *repo = NULL((void *)0);
8011 struct got_fileindex *fileindex = NULL((void *)0);
8012 char *cwd = NULL((void *)0);
8013 struct got_reference *branch = NULL((void *)0);
8014 struct got_reference *new_base_branch = NULL((void *)0), *tmp_branch = NULL((void *)0);
8015 struct got_object_id *commit_id = NULL((void *)0), *parent_id = NULL((void *)0);
8016 struct got_object_id *resume_commit_id = NULL((void *)0);
8017 struct got_object_id *branch_head_commit_id = NULL((void *)0), *yca_id = NULL((void *)0);
8018 struct got_commit_object *commit = NULL((void *)0);
8019 int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0;
8020 int histedit_in_progress = 0, create_backup = 1, list_backups = 0;
8021 unsigned char rebase_status = GOT_STATUS_NO_CHANGE' ';
8022 struct got_object_id_queue commits;
8023 struct got_pathlist_head merged_paths;
8024 const struct got_object_id_queue *parent_ids;
8025 struct got_object_qid *qid, *pid;
8026
8027 SIMPLEQ_INIT(&commits)do { (&commits)->sqh_first = ((void *)0); (&commits
)->sqh_last = &(&commits)->sqh_first; } while (
0)
;
8028 TAILQ_INIT(&merged_paths)do { (&merged_paths)->tqh_first = ((void *)0); (&merged_paths
)->tqh_last = &(&merged_paths)->tqh_first; } while
(0)
;
8029
8030 while ((ch = getopt(argc, argv, "acl")) != -1) {
8031 switch (ch) {
8032 case 'a':
8033 abort_rebase = 1;
8034 break;
8035 case 'c':
8036 continue_rebase = 1;
8037 break;
8038 case 'l':
8039 list_backups = 1;
8040 break;
8041 default:
8042 usage_rebase();
8043 /* NOTREACHED */
8044 }
8045 }
8046
8047 argc -= optind;
8048 argv += optind;
8049
8050#ifndef PROFILE
8051 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8052 "unveil", NULL((void *)0)) == -1)
8053 err(1, "pledge");
8054#endif
8055 if (list_backups) {
8056 if (abort_rebase)
8057 option_conflict('l', 'a');
8058 if (continue_rebase)
8059 option_conflict('l', 'c');
8060 if (argc != 0 && argc != 1)
8061 usage_rebase();
8062 } else {
8063 if (abort_rebase && continue_rebase)
8064 usage_rebase();
8065 else if (abort_rebase || continue_rebase) {
8066 if (argc != 0)
8067 usage_rebase();
8068 } else if (argc != 1)
8069 usage_rebase();
8070 }
8071
8072 cwd = getcwd(NULL((void *)0), 0);
8073 if (cwd == NULL((void *)0)) {
8074 error = got_error_from_errno("getcwd");
8075 goto done;
8076 }
8077 error = got_worktree_open(&worktree, cwd);
8078 if (error) {
8079 if (list_backups) {
8080 if (error->code != GOT_ERR_NOT_WORKTREE60)
8081 goto done;
8082 } else {
8083 if (error->code == GOT_ERR_NOT_WORKTREE60)
8084 error = wrap_not_worktree_error(error,
8085 "rebase", cwd);
8086 goto done;
8087 }
8088 }
8089
8090 error = got_repo_open(&repo,
8091 worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL((void *)0));
8092 if (error != NULL((void *)0))
8093 goto done;
8094
8095 error = apply_unveil(got_repo_get_path(repo), 0,
8096 worktree ? got_worktree_get_root_path(worktree) : NULL((void *)0));
8097 if (error)
8098 goto done;
8099
8100 if (list_backups) {
8101 error = list_backup_refs(GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX"refs/got/backup/rebase",
8102 argc == 1 ? argv[0] : NULL((void *)0), repo);
8103 goto done; /* nothing else to do */
8104 }
8105
8106 error = got_worktree_histedit_in_progress(&histedit_in_progress,
8107 worktree);
8108 if (error)
8109 goto done;
8110 if (histedit_in_progress) {
8111 error = got_error(GOT_ERR_HISTEDIT_BUSY96);
8112 goto done;
8113 }
8114
8115 error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
8116 if (error)
8117 goto done;
8118
8119 if (abort_rebase) {
8120 struct got_update_progress_arg upa;
8121 if (!rebase_in_progress) {
8122 error = got_error(GOT_ERR_NOT_REBASING85);
8123 goto done;
8124 }
8125 error = got_worktree_rebase_continue(&resume_commit_id,
8126 &new_base_branch, &tmp_branch, &branch, &fileindex,
8127 worktree, repo);
8128 if (error)
8129 goto done;
8130 printf("Switching work tree to %s\n",
8131 got_ref_get_symref_target(new_base_branch));
8132 memset(&upa, 0, sizeof(upa));
8133 error = got_worktree_rebase_abort(worktree, fileindex, repo,
8134 new_base_branch, update_progress, &upa);
8135 if (error)
8136 goto done;
8137 printf("Rebase of %s aborted\n", got_ref_get_name(branch));
8138 print_update_progress_stats(&upa);
8139 goto done; /* nothing else to do */
8140 }
8141
8142 if (continue_rebase) {
8143 if (!rebase_in_progress) {
8144 error = got_error(GOT_ERR_NOT_REBASING85);
8145 goto done;
8146 }
8147 error = got_worktree_rebase_continue(&resume_commit_id,
8148 &new_base_branch, &tmp_branch, &branch, &fileindex,
8149 worktree, repo);
8150 if (error)
8151 goto done;
8152
8153 error = rebase_commit(NULL((void *)0), worktree, fileindex, tmp_branch,
8154 resume_commit_id, repo);
8155 if (error)
8156 goto done;
8157
8158 yca_id = got_object_id_dup(resume_commit_id);
8159 if (yca_id == NULL((void *)0)) {
8160 error = got_error_from_errno("got_object_id_dup");
8161 goto done;
8162 }
8163 } else {
8164 error = got_ref_open(&branch, repo, argv[0], 0);
8165 if (error != NULL((void *)0))
8166 goto done;
8167 }
8168
8169 error = got_ref_resolve(&branch_head_commit_id, repo, branch);
8170 if (error)
8171 goto done;
8172
8173 if (!continue_rebase) {
8174 struct got_object_id *base_commit_id;
8175
8176 base_commit_id = got_worktree_get_base_commit_id(worktree);
8177 error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
8178 base_commit_id, branch_head_commit_id, repo,
8179 check_cancelled, NULL((void *)0));
8180 if (error)
8181 goto done;
8182 if (yca_id == NULL((void *)0)) {
8183 error = got_error_msg(GOT_ERR_ANCESTRY55,
8184 "specified branch shares no common ancestry "
8185 "with work tree's branch");
8186 goto done;
8187 }
8188
8189 error = check_same_branch(base_commit_id, branch, yca_id, repo);
8190 if (error) {
8191 if (error->code != GOT_ERR_ANCESTRY55)
8192 goto done;
8193 error = NULL((void *)0);
8194 } else {
8195 static char msg[128];
8196 snprintf(msg, sizeof(msg),
8197 "%s is already based on %s",
8198 got_ref_get_name(branch),
8199 got_worktree_get_head_ref_name(worktree));
8200 error = got_error_msg(GOT_ERR_SAME_BRANCH79, msg);
8201 goto done;
8202 }
8203 error = got_worktree_rebase_prepare(&new_base_branch,
8204 &tmp_branch, &fileindex, worktree, branch, repo);
8205 if (error)
8206 goto done;
8207 }
8208
8209 commit_id = branch_head_commit_id;
8210 error = got_object_open_as_commit(&commit, repo, commit_id);
8211 if (error)
8212 goto done;
8213
8214 parent_ids = got_object_commit_get_parent_ids(commit);
8215 pid = SIMPLEQ_FIRST(parent_ids)((parent_ids)->sqh_first);
8216 if (pid == NULL((void *)0)) {
8217 if (!continue_rebase) {
8218 struct got_update_progress_arg upa;
8219 memset(&upa, 0, sizeof(upa));
8220 error = got_worktree_rebase_abort(worktree, fileindex,
8221 repo, new_base_branch, update_progress, &upa);
8222 if (error)
8223 goto done;
8224 printf("Rebase of %s aborted\n",
8225 got_ref_get_name(branch));
8226 print_update_progress_stats(&upa);
8227
8228 }
8229 error = got_error(GOT_ERR_EMPTY_REBASE86);
8230 goto done;
8231 }
8232 error = collect_commits(&commits, commit_id, pid->id,
8233 yca_id, got_worktree_get_path_prefix(worktree),
8234 GOT_ERR_REBASE_PATH89, repo);
8235 got_object_commit_close(commit);
8236 commit = NULL((void *)0);
8237 if (error)
8238 goto done;
8239
8240 if (SIMPLEQ_EMPTY(&commits)(((&commits)->sqh_first) == ((void *)0))) {
8241 if (continue_rebase) {
8242 error = rebase_complete(worktree, fileindex,
8243 branch, new_base_branch, tmp_branch, repo,
8244 create_backup);
8245 goto done;
8246 } else {
8247 /* Fast-forward the reference of the branch. */
8248 struct got_object_id *new_head_commit_id;
8249 char *id_str;
8250 error = got_ref_resolve(&new_head_commit_id, repo,
8251 new_base_branch);
8252 if (error)
8253 goto done;
8254 error = got_object_id_str(&id_str, new_head_commit_id);
8255 printf("Forwarding %s to commit %s\n",
8256 got_ref_get_name(branch), id_str);
8257 free(id_str);
8258 error = got_ref_change_ref(branch,
8259 new_head_commit_id);
8260 if (error)
8261 goto done;
8262 /* No backup needed since objects did not change. */
8263 create_backup = 0;
8264 }
8265 }
8266
8267 pid = NULL((void *)0);
8268 SIMPLEQ_FOREACH(qid, &commits, entry)for((qid) = ((&commits)->sqh_first); (qid) != ((void *
)0); (qid) = ((qid)->entry.sqe_next))
{
8269 struct got_update_progress_arg upa;
8270
8271 commit_id = qid->id;
8272 parent_id = pid ? pid->id : yca_id;
8273 pid = qid;
8274
8275 memset(&upa, 0, sizeof(upa));
8276 error = got_worktree_rebase_merge_files(&merged_paths,
8277 worktree, fileindex, parent_id, commit_id, repo,
8278 update_progress, &upa, check_cancelled, NULL((void *)0));
8279 if (error)
8280 goto done;
8281
8282 print_update_progress_stats(&upa);
8283 if (upa.conflicts > 0)
8284 rebase_status = GOT_STATUS_CONFLICT'C';
8285
8286 if (rebase_status == GOT_STATUS_CONFLICT'C') {
8287 error = show_rebase_merge_conflict(qid->id, repo);
8288 if (error)
8289 goto done;
8290 got_worktree_rebase_pathlist_free(&merged_paths);
8291 break;
8292 }
8293
8294 error = rebase_commit(&merged_paths, worktree, fileindex,
8295 tmp_branch, commit_id, repo);
8296 got_worktree_rebase_pathlist_free(&merged_paths);
8297 if (error)
8298 goto done;
8299 }
8300
8301 if (rebase_status == GOT_STATUS_CONFLICT'C') {
8302 error = got_worktree_rebase_postpone(worktree, fileindex);
8303 if (error)
8304 goto done;
8305 error = got_error_msg(GOT_ERR_CONFLICTS82,
8306 "conflicts must be resolved before rebasing can continue");
8307 } else
8308 error = rebase_complete(worktree, fileindex, branch,
8309 new_base_branch, tmp_branch, repo, create_backup);
8310done:
8311 got_object_id_queue_free(&commits);
8312 free(branch_head_commit_id);
8313 free(resume_commit_id);
8314 free(yca_id);
8315 if (commit)
8316 got_object_commit_close(commit);
8317 if (branch)
8318 got_ref_close(branch);
8319 if (new_base_branch)
8320 got_ref_close(new_base_branch);
8321 if (tmp_branch)
8322 got_ref_close(tmp_branch);
8323 if (worktree)
8324 got_worktree_close(worktree);
8325 if (repo)
8326 got_repo_close(repo);
8327 return error;
8328}
8329
8330__dead__attribute__((__noreturn__)) static void
8331usage_histedit(void)
8332{
8333 fprintf(stderr(&__sF[2]), "usage: %s histedit [-a] [-c] [-f] "
8334 "[-F histedit-script] [-m] [-l] [branch]\n", getprogname());
8335 exit(1);
8336}
8337
8338#define GOT_HISTEDIT_PICK'p' 'p'
8339#define GOT_HISTEDIT_EDIT'e' 'e'
8340#define GOT_HISTEDIT_FOLD'f' 'f'
8341#define GOT_HISTEDIT_DROP'd' 'd'
8342#define GOT_HISTEDIT_MESG'm' 'm'
8343
8344static struct got_histedit_cmd {
8345 unsigned char code;
8346 const char *name;
8347 const char *desc;
8348} got_histedit_cmds[] = {
8349 { GOT_HISTEDIT_PICK'p', "pick", "use commit" },
8350 { GOT_HISTEDIT_EDIT'e', "edit", "use commit but stop for amending" },
8351 { GOT_HISTEDIT_FOLD'f', "fold", "combine with next commit that will "
8352 "be used" },
8353 { GOT_HISTEDIT_DROP'd', "drop", "remove commit from history" },
8354 { GOT_HISTEDIT_MESG'm', "mesg",
8355 "single-line log message for commit above (open editor if empty)" },
8356};
8357
8358struct got_histedit_list_entry {
8359 TAILQ_ENTRY(got_histedit_list_entry)struct { struct got_histedit_list_entry *tqe_next; struct got_histedit_list_entry
**tqe_prev; }
entry;
8360 struct got_object_id *commit_id;
8361 const struct got_histedit_cmd *cmd;
8362 char *logmsg;
8363};
8364TAILQ_HEAD(got_histedit_list, got_histedit_list_entry)struct got_histedit_list { struct got_histedit_list_entry *tqh_first
; struct got_histedit_list_entry **tqh_last; }
;
8365
8366static const struct got_error *
8367histedit_write_commit(struct got_object_id *commit_id, const char *cmdname,
8368 FILE *f, struct got_repository *repo)
8369{
8370 const struct got_error *err = NULL((void *)0);
8371 char *logmsg = NULL((void *)0), *id_str = NULL((void *)0);
8372 struct got_commit_object *commit = NULL((void *)0);
8373 int n;
8374
8375 err = got_object_open_as_commit(&commit, repo, commit_id);
8376 if (err)
8377 goto done;
8378
8379 err = get_short_logmsg(&logmsg, 34, commit);
8380 if (err)
8381 goto done;
8382
8383 err = got_object_id_str(&id_str, commit_id);
8384 if (err)
8385 goto done;
8386
8387 n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg);
8388 if (n < 0)
8389 err = got_ferror(f, GOT_ERR_IO6);
8390done:
8391 if (commit)
8392 got_object_commit_close(commit);
8393 free(id_str);
8394 free(logmsg);
8395 return err;
8396}
8397
8398static const struct got_error *
8399histedit_write_commit_list(struct got_object_id_queue *commits,
8400 FILE *f, int edit_logmsg_only, int fold_only, struct got_repository *repo)
8401{
8402 const struct got_error *err = NULL((void *)0);
8403 struct got_object_qid *qid;
8404 const char *histedit_cmd = NULL((void *)0);
8405
8406 if (SIMPLEQ_EMPTY(commits)(((commits)->sqh_first) == ((void *)0)))
8407 return got_error(GOT_ERR_EMPTY_HISTEDIT91);
8408
8409 SIMPLEQ_FOREACH(qid, commits, entry)for((qid) = ((commits)->sqh_first); (qid) != ((void *)0); (
qid) = ((qid)->entry.sqe_next))
{
8410 histedit_cmd = got_histedit_cmds[0].name;
8411 if (fold_only && SIMPLEQ_NEXT(qid, entry)((qid)->entry.sqe_next) != NULL((void *)0))
8412 histedit_cmd = "fold";
8413 err = histedit_write_commit(qid->id, histedit_cmd, f, repo);
8414 if (err)
8415 break;
8416 if (edit_logmsg_only) {
8417 int n = fprintf(f, "%c\n", GOT_HISTEDIT_MESG'm');
8418 if (n < 0) {
8419 err = got_ferror(f, GOT_ERR_IO6);
8420 break;
8421 }
8422 }
8423 }
8424
8425 return err;
8426}
8427
8428static const struct got_error *
8429write_cmd_list(FILE *f, const char *branch_name,
8430 struct got_object_id_queue *commits)
8431{
8432 const struct got_error *err = NULL((void *)0);
8433 size_t i;
8434 int n;
8435 char *id_str;
8436 struct got_object_qid *qid;
8437
8438 qid = SIMPLEQ_FIRST(commits)((commits)->sqh_first);
8439 err = got_object_id_str(&id_str, qid->id);
8440 if (err)
8441 return err;
8442
8443 n = fprintf(f,
8444 "# Editing the history of branch '%s' starting at\n"
8445 "# commit %s\n"
8446 "# Commits will be processed in order from top to "
8447 "bottom of this file.\n", branch_name, id_str);
8448 if (n < 0) {
8449 err = got_ferror(f, GOT_ERR_IO6);
8450 goto done;
8451 }
8452
8453 n = fprintf(f, "# Available histedit commands:\n");
8454 if (n < 0) {
8455 err = got_ferror(f, GOT_ERR_IO6);
8456 goto done;
8457 }
8458
8459 for (i = 0; i < nitems(got_histedit_cmds)(sizeof((got_histedit_cmds)) / sizeof((got_histedit_cmds)[0])
)
; i++) {
8460 struct got_histedit_cmd *cmd = &got_histedit_cmds[i];
8461 n = fprintf(f, "# %s (%c): %s\n", cmd->name, cmd->code,
8462 cmd->desc);
8463 if (n < 0) {
8464 err = got_ferror(f, GOT_ERR_IO6);
8465 break;
8466 }
8467 }
8468done:
8469 free(id_str);
8470 return err;
8471}
8472
8473static const struct got_error *
8474histedit_syntax_error(int lineno)
8475{
8476 static char msg[42];
8477 int ret;
8478
8479 ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d",
8480 lineno);
8481 if (ret == -1 || ret >= sizeof(msg))
8482 return got_error(GOT_ERR_HISTEDIT_SYNTAX93);
8483
8484 return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX93, msg);
8485}
8486
8487static const struct got_error *
8488append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle,
8489 char *logmsg, struct got_repository *repo)
8490{
8491 const struct got_error *err;
8492 struct got_commit_object *folded_commit = NULL((void *)0);
8493 char *id_str, *folded_logmsg = NULL((void *)0);
8494
8495 err = got_object_id_str(&id_str, hle->commit_id);
8496 if (err)
8497 return err;
8498
8499 err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id);
8500 if (err)
8501 goto done;
8502
8503 err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit);
8504 if (err)
8505 goto done;
8506 if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s",
8507 logmsg ? logmsg : "", logmsg ? "\n" : "", id_str,
8508 folded_logmsg) == -1) {
8509 err = got_error_from_errno("asprintf");
8510 }
8511done:
8512 if (folded_commit)
8513 got_object_commit_close(folded_commit);
8514 free(id_str);
8515 free(folded_logmsg);
8516 return err;
8517}
8518
8519static struct got_histedit_list_entry *
8520get_folded_commits(struct got_histedit_list_entry *hle)
8521{
8522 struct got_histedit_list_entry *prev, *folded = NULL((void *)0);
8523
8524 prev = TAILQ_PREV(hle, got_histedit_list, entry)(*(((struct got_histedit_list *)((hle)->entry.tqe_prev))->
tqh_last))
;
8525 while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD'f' ||
8526 prev->cmd->code == GOT_HISTEDIT_DROP'd')) {
8527 if (prev->cmd->code == GOT_HISTEDIT_FOLD'f')
8528 folded = prev;
8529 prev = TAILQ_PREV(prev, got_histedit_list, entry)(*(((struct got_histedit_list *)((prev)->entry.tqe_prev))->
tqh_last))
;
8530 }
8531
8532 return folded;
8533}
8534
8535static const struct got_error *
8536histedit_edit_logmsg(struct got_histedit_list_entry *hle,
8537 struct got_repository *repo)
8538{
8539 char *logmsg_path = NULL((void *)0), *id_str = NULL((void *)0), *orig_logmsg = NULL((void *)0);
8540 char *logmsg = NULL((void *)0), *new_msg = NULL((void *)0), *editor = NULL((void *)0);
8541 const struct got_error *err = NULL((void *)0);
8542 struct got_commit_object *commit = NULL((void *)0);
8543 int logmsg_len;
8544 int fd;
8545 struct got_histedit_list_entry *folded = NULL((void *)0);
8546
8547 err = got_object_open_as_commit(&commit, repo, hle->commit_id);
8548 if (err)
8549 return err;
8550
8551 folded = get_folded_commits(hle);
8552 if (folded) {
8553 while (folded != hle) {
8554 if (folded->cmd->code == GOT_HISTEDIT_DROP'd') {
8555 folded = TAILQ_NEXT(folded, entry)((folded)->entry.tqe_next);
8556 continue;
8557 }
8558 err = append_folded_commit_msg(&new_msg, folded,
8559 logmsg, repo);
8560 if (err)
8561 goto done;
8562 free(logmsg);
8563 logmsg = new_msg;
8564 folded = TAILQ_NEXT(folded, entry)((folded)->entry.tqe_next);
8565 }
8566 }
8567
8568 err = got_object_id_str(&id_str, hle->commit_id);
8569 if (err)
8570 goto done;
8571 err = got_object_commit_get_logmsg(&orig_logmsg, commit);
8572 if (err)
8573 goto done;
8574 logmsg_len = asprintf(&new_msg,
8575 "%s\n# original log message of commit %s: %s",
8576 logmsg ? logmsg : "", id_str, orig_logmsg);
8577 if (logmsg_len == -1) {
8578 err = got_error_from_errno("asprintf");
8579 goto done;
8580 }
8581 free(logmsg);
8582 logmsg = new_msg;
8583
8584 err = got_object_id_str(&id_str, hle->commit_id);
8585 if (err)
8586 goto done;
8587
8588 err = got_opentemp_named_fd(&logmsg_path, &fd,
8589 GOT_TMPDIR_STR"/tmp" "/got-logmsg");
8590 if (err)
8591 goto done;
8592
8593 write(fd, logmsg, logmsg_len);
8594 close(fd);
8595
8596 err = get_editor(&editor);
8597 if (err)
8598 goto done;
8599
8600 err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg,
8601 logmsg_len, 0);
8602 if (err) {
8603 if (err->code != GOT_ERR_COMMIT_MSG_EMPTY74)
8604 goto done;
8605 err = NULL((void *)0);
8606 hle->logmsg = strdup(new_msg);
8607 if (hle->logmsg == NULL((void *)0))
8608 err = got_error_from_errno("strdup");
8609 }
8610done:
8611 if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL((void *)0))
8612 err = got_error_from_errno2("unlink", logmsg_path);
8613 free(logmsg_path);
8614 free(logmsg);
8615 free(orig_logmsg);
8616 free(editor);
8617 if (commit)
8618 got_object_commit_close(commit);
8619 return err;
8620}
8621
8622static const struct got_error *
8623histedit_parse_list(struct got_histedit_list *histedit_cmds,
8624 FILE *f, struct got_repository *repo)
8625{
8626 const struct got_error *err = NULL((void *)0);
8627 char *line = NULL((void *)0), *p, *end;
8628 size_t i, size;
8629 ssize_t len;
8630 int lineno = 0;
8631 const struct got_histedit_cmd *cmd;
8632 struct got_object_id *commit_id = NULL((void *)0);
8633 struct got_histedit_list_entry *hle = NULL((void *)0);
8634
8635 for (;;) {
8636 len = getline(&line, &size, f);
8637 if (len == -1) {
8638 const struct got_error *getline_err;
8639 if (feof(f)(!__isthreaded ? (((f)->_flags & 0x0020) != 0) : (feof
)(f))
)
8640 break;
8641 getline_err = got_error_from_errno("getline");
8642 err = got_ferror(f, getline_err->code);
8643 break;
8644 }
8645 lineno++;
8646 p = line;
8647 while (isspace((unsigned char)p[0]))
8648 p++;
8649 if (p[0] == '#' || p[0] == '\0') {
8650 free(line);
8651 line = NULL((void *)0);
8652 continue;
8653 }
8654 cmd = NULL((void *)0);
8655 for (i = 0; i < nitems(got_histedit_cmds)(sizeof((got_histedit_cmds)) / sizeof((got_histedit_cmds)[0])
)
; i++) {
8656 cmd = &got_histedit_cmds[i];
8657 if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 &&
8658 isspace((unsigned char)p[strlen(cmd->name)])) {
8659 p += strlen(cmd->name);
8660 break;
8661 }
8662 if (p[0] == cmd->code && isspace((unsigned char)p[1])) {
8663 p++;
8664 break;
8665 }
8666 }
8667 if (i == nitems(got_histedit_cmds)(sizeof((got_histedit_cmds)) / sizeof((got_histedit_cmds)[0])
)
) {
8668 err = histedit_syntax_error(lineno);
8669 break;
8670 }
8671 while (isspace((unsigned char)p[0]))
8672 p++;
8673 if (cmd->code == GOT_HISTEDIT_MESG'm') {
8674 if (hle == NULL((void *)0) || hle->logmsg != NULL((void *)0)) {
8675 err = got_error(GOT_ERR_HISTEDIT_CMD97);
8676 break;
8677 }
8678 if (p[0] == '\0') {
8679 err = histedit_edit_logmsg(hle, repo);
8680 if (err)
8681 break;
8682 } else {
8683 hle->logmsg = strdup(p);
8684 if (hle->logmsg == NULL((void *)0)) {
8685 err = got_error_from_errno("strdup");
8686 break;
8687 }
8688 }
8689 free(line);
8690 line = NULL((void *)0);
8691 continue;
8692 } else {
8693 end = p;
8694 while (end[0] && !isspace((unsigned char)end[0]))
8695 end++;
8696 *end = '\0';
8697
8698 err = got_object_resolve_id_str(&commit_id, repo, p);
8699 if (err) {
8700 /* override error code */
8701 err = histedit_syntax_error(lineno);
8702 break;
8703 }
8704 }
8705 hle = malloc(sizeof(*hle));
8706 if (hle == NULL((void *)0)) {
8707 err = got_error_from_errno("malloc");
8708 break;
8709 }
8710 hle->cmd = cmd;
8711 hle->commit_id = commit_id;
8712 hle->logmsg = NULL((void *)0);
8713 commit_id = NULL((void *)0);
8714 free(line);
8715 line = NULL((void *)0);
8716 TAILQ_INSERT_TAIL(histedit_cmds, hle, entry)do { (hle)->entry.tqe_next = ((void *)0); (hle)->entry.
tqe_prev = (histedit_cmds)->tqh_last; *(histedit_cmds)->
tqh_last = (hle); (histedit_cmds)->tqh_last = &(hle)->
entry.tqe_next; } while (0)
;
8717 }
8718
8719 free(line);
8720 free(commit_id);
8721 return err;
8722}
8723
8724static const struct got_error *
8725histedit_check_script(struct got_histedit_list *histedit_cmds,
8726 struct got_object_id_queue *commits, struct got_repository *repo)
8727{
8728 const struct got_error *err = NULL((void *)0);
8729 struct got_object_qid *qid;
8730 struct got_histedit_list_entry *hle;
8731 static char msg[92];
8732 char *id_str;
8733
8734 if (TAILQ_EMPTY(histedit_cmds)(((histedit_cmds)->tqh_first) == ((void *)0)))
8735 return got_error_msg(GOT_ERR_EMPTY_HISTEDIT91,
8736 "histedit script contains no commands");
8737 if (SIMPLEQ_EMPTY(commits)(((commits)->sqh_first) == ((void *)0)))
8738 return got_error(GOT_ERR_EMPTY_HISTEDIT91);
8739
8740 TAILQ_FOREACH(hle, histedit_cmds, entry)for((hle) = ((histedit_cmds)->tqh_first); (hle) != ((void *
)0); (hle) = ((hle)->entry.tqe_next))
{
8741 struct got_histedit_list_entry *hle2;
8742 TAILQ_FOREACH(hle2, histedit_cmds, entry)for((hle2) = ((histedit_cmds)->tqh_first); (hle2) != ((void
*)0); (hle2) = ((hle2)->entry.tqe_next))
{
8743 if (hle == hle2)
8744 continue;
8745 if (got_object_id_cmp(hle->commit_id,
8746 hle2->commit_id) != 0)
8747 continue;
8748 err = got_object_id_str(&id_str, hle->commit_id);
8749 if (err)
8750 return err;
8751 snprintf(msg, sizeof(msg), "commit %s is listed "
8752 "more than once in histedit script", id_str);
8753 free(id_str);
8754 return got_error_msg(GOT_ERR_HISTEDIT_CMD97, msg);
8755 }
8756 }
8757
8758 SIMPLEQ_FOREACH(qid, commits, entry)for((qid) = ((commits)->sqh_first); (qid) != ((void *)0); (
qid) = ((qid)->entry.sqe_next))
{
8759 TAILQ_FOREACH(hle, histedit_cmds, entry)for((hle) = ((histedit_cmds)->tqh_first); (hle) != ((void *
)0); (hle) = ((hle)->entry.tqe_next))
{
8760 if (got_object_id_cmp(qid->id, hle->commit_id) == 0)
8761 break;
8762 }
8763 if (hle == NULL((void *)0)) {
8764 err = got_object_id_str(&id_str, qid->id);
8765 if (err)
8766 return err;
8767 snprintf(msg, sizeof(msg),
8768 "commit %s missing from histedit script", id_str);
8769 free(id_str);
8770 return got_error_msg(GOT_ERR_HISTEDIT_CMD97, msg);
8771 }
8772 }
8773
8774 hle = TAILQ_LAST(histedit_cmds, got_histedit_list)(*(((struct got_histedit_list *)((histedit_cmds)->tqh_last
))->tqh_last))
;
8775 if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD'f')
8776 return got_error_msg(GOT_ERR_HISTEDIT_CMD97,
8777 "last commit in histedit script cannot be folded");
8778
8779 return NULL((void *)0);
8780}
8781
8782static const struct got_error *
8783histedit_run_editor(struct got_histedit_list *histedit_cmds,
8784 const char *path, struct got_object_id_queue *commits,
8785 struct got_repository *repo)
8786{
8787 const struct got_error *err = NULL((void *)0);
8788 char *editor;
8789 FILE *f = NULL((void *)0);
8790
8791 err = get_editor(&editor);
8792 if (err)
8793 return err;
8794
8795 if (spawn_editor(editor, path) == -1) {
8796 err = got_error_from_errno("failed spawning editor");
8797 goto done;
8798 }
8799
8800 f = fopen(path, "r");
8801 if (f == NULL((void *)0)) {
8802 err = got_error_from_errno("fopen");
8803 goto done;
8804 }
8805 err = histedit_parse_list(histedit_cmds, f, repo);
8806 if (err)
8807 goto done;
8808
8809 err = histedit_check_script(histedit_cmds, commits, repo);
8810done:
8811 if (f && fclose(f) == EOF(-1) && err == NULL((void *)0))
8812 err = got_error_from_errno("fclose");
8813 free(editor);
8814 return err;
8815}
8816
8817static const struct got_error *
8818histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *,
8819 struct got_object_id_queue *, const char *, const char *,
8820 struct got_repository *);
8821
8822static const struct got_error *
8823histedit_edit_script(struct got_histedit_list *histedit_cmds,
8824 struct got_object_id_queue *commits, const char *branch_name,
8825 int edit_logmsg_only, int fold_only, struct got_repository *repo)
8826{
8827 const struct got_error *err;
8828 FILE *f = NULL((void *)0);
8829 char *path = NULL((void *)0);
8830
8831 err = got_opentemp_named(&path, &f, "got-histedit");
8832 if (err)
8833 return err;
8834
8835 err = write_cmd_list(f, branch_name, commits);
8836 if (err)
8837 goto done;
8838
8839 err = histedit_write_commit_list(commits, f, edit_logmsg_only,
8840 fold_only, repo);
8841 if (err)
8842 goto done;
8843
8844 if (edit_logmsg_only || fold_only) {
8845 rewind(f);
8846 err = histedit_parse_list(histedit_cmds, f, repo);
8847 } else {
8848 if (fclose(f) == EOF(-1)) {
8849 err = got_error_from_errno("fclose");
8850 goto done;
8851 }
8852 f = NULL((void *)0);
8853 err = histedit_run_editor(histedit_cmds, path, commits, repo);
8854 if (err) {
8855 if (err->code != GOT_ERR_HISTEDIT_SYNTAX93 &&
8856 err->code != GOT_ERR_HISTEDIT_CMD97)
8857 goto done;
8858 err = histedit_edit_list_retry(histedit_cmds, err,
8859 commits, path, branch_name, repo);
8860 }
8861 }
8862done:
8863 if (f && fclose(f) == EOF(-1) && err == NULL((void *)0))
8864 err = got_error_from_errno("fclose");
8865 if (path && unlink(path) != 0 && err == NULL((void *)0))
8866 err = got_error_from_errno2("unlink", path);
8867 free(path);
8868 return err;
8869}
8870
8871static const struct got_error *
8872histedit_save_list(struct got_histedit_list *histedit_cmds,
8873 struct got_worktree *worktree, struct got_repository *repo)
8874{
8875 const struct got_error *err = NULL((void *)0);
8876 char *path = NULL((void *)0);
8877 FILE *f = NULL((void *)0);
8878 struct got_histedit_list_entry *hle;
8879 struct got_commit_object *commit = NULL((void *)0);
8880
8881 err = got_worktree_get_histedit_script_path(&path, worktree);
8882 if (err)
8883 return err;
8884
8885 f = fopen(path, "w");
8886 if (f == NULL((void *)0)) {
8887 err = got_error_from_errno2("fopen", path);
8888 goto done;
8889 }
8890 TAILQ_FOREACH(hle, histedit_cmds, entry)for((hle) = ((histedit_cmds)->tqh_first); (hle) != ((void *
)0); (hle) = ((hle)->entry.tqe_next))
{
8891 err = histedit_write_commit(hle->commit_id, hle->cmd->name, f,
8892 repo);
8893 if (err)
8894 break;
8895
8896 if (hle->logmsg) {
8897 int n = fprintf(f, "%c %s\n",
8898 GOT_HISTEDIT_MESG'm', hle->logmsg);
8899 if (n < 0) {
8900 err = got_ferror(f, GOT_ERR_IO6);
8901 break;
8902 }
8903 }
8904 }
8905done:
8906 if (f && fclose(f) == EOF(-1) && err == NULL((void *)0))
8907 err = got_error_from_errno("fclose");
8908 free(path);
8909 if (commit)
8910 got_object_commit_close(commit);
8911 return err;
8912}
8913
8914void
8915histedit_free_list(struct got_histedit_list *histedit_cmds)
8916{
8917 struct got_histedit_list_entry *hle;
8918
8919 while ((hle = TAILQ_FIRST(histedit_cmds)((histedit_cmds)->tqh_first))) {
8920 TAILQ_REMOVE(histedit_cmds, hle, entry)do { if (((hle)->entry.tqe_next) != ((void *)0)) (hle)->
entry.tqe_next->entry.tqe_prev = (hle)->entry.tqe_prev;
else (histedit_cmds)->tqh_last = (hle)->entry.tqe_prev
; *(hle)->entry.tqe_prev = (hle)->entry.tqe_next; ; ; }
while (0)
;
8921 free(hle);
8922 }
8923}
8924
8925static const struct got_error *
8926histedit_load_list(struct got_histedit_list *histedit_cmds,
8927 const char *path, struct got_repository *repo)
8928{
8929 const struct got_error *err = NULL((void *)0);
8930 FILE *f = NULL((void *)0);
8931
8932 f = fopen(path, "r");
8933 if (f == NULL((void *)0)) {
8934 err = got_error_from_errno2("fopen", path);
8935 goto done;
8936 }
8937
8938 err = histedit_parse_list(histedit_cmds, f, repo);
8939done:
8940 if (f && fclose(f) == EOF(-1) && err == NULL((void *)0))
8941 err = got_error_from_errno("fclose");
8942 return err;
8943}
8944
8945static const struct got_error *
8946histedit_edit_list_retry(struct got_histedit_list *histedit_cmds,
8947 const struct got_error *edit_err, struct got_object_id_queue *commits,
8948 const char *path, const char *branch_name, struct got_repository *repo)
8949{
8950 const struct got_error *err = NULL((void *)0), *prev_err = edit_err;
8951 int resp = ' ';
8952
8953 while (resp != 'c' && resp != 'r' && resp != 'a') {
8954 printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
8955 "or (a)bort: ", getprogname(), prev_err->msg);
8956 resp = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
;
8957 if (resp == '\n')
8958 resp = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
;
8959 if (resp == 'c') {
8960 histedit_free_list(histedit_cmds);
8961 err = histedit_run_editor(histedit_cmds, path, commits,
8962 repo);
8963 if (err) {
8964 if (err->code != GOT_ERR_HISTEDIT_SYNTAX93 &&
8965 err->code != GOT_ERR_HISTEDIT_CMD97)
8966 break;
8967 prev_err = err;
8968 resp = ' ';
8969 continue;
8970 }
8971 break;
8972 } else if (resp == 'r') {
8973 histedit_free_list(histedit_cmds);
8974 err = histedit_edit_script(histedit_cmds,
8975 commits, branch_name, 0, 0, repo);
8976 if (err) {
8977 if (err->code != GOT_ERR_HISTEDIT_SYNTAX93 &&
8978 err->code != GOT_ERR_HISTEDIT_CMD97)
8979 break;
8980 prev_err = err;
8981 resp = ' ';
8982 continue;
8983 }
8984 break;
8985 } else if (resp == 'a') {
8986 err = got_error(GOT_ERR_HISTEDIT_CANCEL94);
8987 break;
8988 } else
8989 printf("invalid response '%c'\n", resp);
8990 }
8991
8992 return err;
8993}
8994
8995static const struct got_error *
8996histedit_complete(struct got_worktree *worktree,
8997 struct got_fileindex *fileindex, struct got_reference *tmp_branch,
8998 struct got_reference *branch, struct got_repository *repo)
8999{
9000 printf("Switching work tree to %s\n",
9001 got_ref_get_symref_target(branch));
9002 return got_worktree_histedit_complete(worktree, fileindex, tmp_branch,
9003 branch, repo);
9004}
9005
9006static const struct got_error *
9007show_histedit_progress(struct got_commit_object *commit,
9008 struct got_histedit_list_entry *hle, struct got_object_id *new_id)
9009{
9010 const struct got_error *err;
9011 char *old_id_str = NULL((void *)0), *new_id_str = NULL((void *)0), *logmsg = NULL((void *)0);
9012
9013 err = got_object_id_str(&old_id_str, hle->commit_id);
9014 if (err)
9015 goto done;
9016
9017 if (new_id) {
9018 err = got_object_id_str(&new_id_str, new_id);
9019 if (err)
9020 goto done;
9021 }
9022
9023 old_id_str[12] = '\0';
9024 if (new_id_str)
9025 new_id_str[12] = '\0';
9026
9027 if (hle->logmsg) {
9028 logmsg = strdup(hle->logmsg);
9029 if (logmsg == NULL((void *)0)) {
9030 err = got_error_from_errno("strdup");
9031 goto done;
9032 }
9033 trim_logmsg(logmsg, 42);
9034 } else {
9035 err = get_short_logmsg(&logmsg, 42, commit);
9036 if (err)
9037 goto done;
9038 }
9039
9040 switch (hle->cmd->code) {
9041 case GOT_HISTEDIT_PICK'p':
9042 case GOT_HISTEDIT_EDIT'e':
9043 printf("%s -> %s: %s\n", old_id_str,
9044 new_id_str ? new_id_str : "no-op change", logmsg);
9045 break;
9046 case GOT_HISTEDIT_DROP'd':
9047 case GOT_HISTEDIT_FOLD'f':
9048 printf("%s -> %s commit: %s\n", old_id_str, hle->cmd->name,
9049 logmsg);
9050 break;
9051 default:
9052 break;
9053 }
9054done:
9055 free(old_id_str);
9056 free(new_id_str);
9057 return err;
9058}
9059
9060static const struct got_error *
9061histedit_commit(struct got_pathlist_head *merged_paths,
9062 struct got_worktree *worktree, struct got_fileindex *fileindex,
9063 struct got_reference *tmp_branch, struct got_histedit_list_entry *hle,
9064 struct got_repository *repo)
9065{
9066 const struct got_error *err;
9067 struct got_commit_object *commit;
9068 struct got_object_id *new_commit_id;
9069
9070 if ((hle->cmd->code == GOT_HISTEDIT_EDIT'e' || get_folded_commits(hle))
9071 && hle->logmsg == NULL((void *)0)) {
9072 err = histedit_edit_logmsg(hle, repo);
9073 if (err)
9074 return err;
9075 }
9076
9077 err = got_object_open_as_commit(&commit, repo, hle->commit_id);
9078 if (err)
9079 return err;
9080
9081 err = got_worktree_histedit_commit(&new_commit_id, merged_paths,
9082 worktree, fileindex, tmp_branch, commit, hle->commit_id,
9083 hle->logmsg, repo);
9084 if (err) {
9085 if (err->code != GOT_ERR_COMMIT_NO_CHANGES76)
9086 goto done;
9087 err = show_histedit_progress(commit, hle, NULL((void *)0));
9088 } else {
9089 err = show_histedit_progress(commit, hle, new_commit_id);
9090 free(new_commit_id);
9091 }
9092done:
9093 got_object_commit_close(commit);
9094 return err;
9095}
9096
9097static const struct got_error *
9098histedit_skip_commit(struct got_histedit_list_entry *hle,
9099 struct got_worktree *worktree, struct got_repository *repo)
9100{
9101 const struct got_error *error;
9102 struct got_commit_object *commit;
9103
9104 error = got_worktree_histedit_skip_commit(worktree, hle->commit_id,
9105 repo);
9106 if (error)
9107 return error;
9108
9109 error = got_object_open_as_commit(&commit, repo, hle->commit_id);
9110 if (error)
9111 return error;
9112
9113 error = show_histedit_progress(commit, hle, NULL((void *)0));
9114 got_object_commit_close(commit);
9115 return error;
9116}
9117
9118static const struct got_error *
9119check_local_changes(void *arg, unsigned char status,
9120 unsigned char staged_status, const char *path,
9121 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
9122 struct got_object_id *commit_id, int dirfd, const char *de_name)
9123{
9124 int *have_local_changes = arg;
9125
9126 switch (status) {
9127 case GOT_STATUS_ADD'A':
9128 case GOT_STATUS_DELETE'D':
9129 case GOT_STATUS_MODIFY'M':
9130 case GOT_STATUS_CONFLICT'C':
9131 *have_local_changes = 1;
9132 return got_error(GOT_ERR_CANCELLED49);
9133 default:
9134 break;
9135 }
9136
9137 switch (staged_status) {
9138 case GOT_STATUS_ADD'A':
9139 case GOT_STATUS_DELETE'D':
9140 case GOT_STATUS_MODIFY'M':
9141 *have_local_changes = 1;
9142 return got_error(GOT_ERR_CANCELLED49);
9143 default:
9144 break;
9145 }
9146
9147 return NULL((void *)0);
9148}
9149
9150static const struct got_error *
9151cmd_histedit(int argc, char *argv[])
9152{
9153 const struct got_error *error = NULL((void *)0);
9154 struct got_worktree *worktree = NULL((void *)0);
9155 struct got_fileindex *fileindex = NULL((void *)0);
9156 struct got_repository *repo = NULL((void *)0);
9157 char *cwd = NULL((void *)0);
9158 struct got_reference *branch = NULL((void *)0);
9159 struct got_reference *tmp_branch = NULL((void *)0);
9160 struct got_object_id *resume_commit_id = NULL((void *)0);
9161 struct got_object_id *base_commit_id = NULL((void *)0);
9162 struct got_object_id *head_commit_id = NULL((void *)0);
9163 struct got_commit_object *commit = NULL((void *)0);
9164 int ch, rebase_in_progress = 0;
9165 struct got_update_progress_arg upa;
9166 int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
9167 int edit_logmsg_only = 0, fold_only = 0;
9168 int list_backups = 0;
9169 const char *edit_script_path = NULL((void *)0);
9170 unsigned char rebase_status = GOT_STATUS_NO_CHANGE' ';
9171 struct got_object_id_queue commits;
9172 struct got_pathlist_head merged_paths;
9173 const struct got_object_id_queue *parent_ids;
9174 struct got_object_qid *pid;
9175 struct got_histedit_list histedit_cmds;
9176 struct got_histedit_list_entry *hle;
9177
9178 SIMPLEQ_INIT(&commits)do { (&commits)->sqh_first = ((void *)0); (&commits
)->sqh_last = &(&commits)->sqh_first; } while (
0)
;
9179 TAILQ_INIT(&histedit_cmds)do { (&histedit_cmds)->tqh_first = ((void *)0); (&
histedit_cmds)->tqh_last = &(&histedit_cmds)->tqh_first
; } while (0)
;
9180 TAILQ_INIT(&merged_paths)do { (&merged_paths)->tqh_first = ((void *)0); (&merged_paths
)->tqh_last = &(&merged_paths)->tqh_first; } while
(0)
;
9181 memset(&upa, 0, sizeof(upa));
9182
9183 while ((ch = getopt(argc, argv, "acfF:ml")) != -1) {
9184 switch (ch) {
9185 case 'a':
9186 abort_edit = 1;
9187 break;
9188 case 'c':
9189 continue_edit = 1;
9190 break;
9191 case 'f':
9192 fold_only = 1;
9193 break;
9194 case 'F':
9195 edit_script_path = optarg;
9196 break;
9197 case 'm':
9198 edit_logmsg_only = 1;
9199 break;
9200 case 'l':
9201 list_backups = 1;
9202 break;
9203 default:
9204 usage_histedit();
9205 /* NOTREACHED */
9206 }
9207 }
9208
9209 argc -= optind;
9210 argv += optind;
9211
9212#ifndef PROFILE
9213 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9214 "unveil", NULL((void *)0)) == -1)
9215 err(1, "pledge");
9216#endif
9217 if (abort_edit && continue_edit)
9218 option_conflict('a', 'c');
9219 if (edit_script_path && edit_logmsg_only)
9220 option_conflict('F', 'm');
9221 if (abort_edit && edit_logmsg_only)
9222 option_conflict('a', 'm');
9223 if (continue_edit && edit_logmsg_only)
9224 option_conflict('c', 'm');
9225 if (abort_edit && fold_only)
9226 option_conflict('a', 'f');
9227 if (continue_edit && fold_only)
9228 option_conflict('c', 'f');
9229 if (fold_only && edit_logmsg_only)
9230 option_conflict('f', 'm');
9231 if (edit_script_path && fold_only)
9232 option_conflict('F', 'f');
9233 if (list_backups) {
9234 if (abort_edit)
9235 option_conflict('l', 'a');
9236 if (continue_edit)
9237 option_conflict('l', 'c');
9238 if (edit_script_path)
9239 option_conflict('l', 'F');
9240 if (edit_logmsg_only)
9241 option_conflict('l', 'm');
9242 if (fold_only)
9243 option_conflict('l', 'f');
9244 if (argc != 0 && argc != 1)
9245 usage_histedit();
9246 } else if (argc != 0)
9247 usage_histedit();
9248
9249 /*
9250 * This command cannot apply unveil(2) in all cases because the
9251 * user may choose to run an editor to edit the histedit script
9252 * and to edit individual commit log messages.
9253 * unveil(2) traverses exec(2); if an editor is used we have to
9254 * apply unveil after edit script and log messages have been written.
9255 * XXX TODO: Make use of unveil(2) where possible.
9256 */
9257
9258 cwd = getcwd(NULL((void *)0), 0);
9259 if (cwd == NULL((void *)0)) {
9260 error = got_error_from_errno("getcwd");
9261 goto done;
9262 }
9263 error = got_worktree_open(&worktree, cwd);
9264 if (error) {
9265 if (list_backups) {
9266 if (error->code != GOT_ERR_NOT_WORKTREE60)
9267 goto done;
9268 } else {
9269 if (error->code == GOT_ERR_NOT_WORKTREE60)
9270 error = wrap_not_worktree_error(error,
9271 "histedit", cwd);
9272 goto done;
9273 }
9274 }
9275
9276 if (list_backups) {
9277 error = got_repo_open(&repo,
9278 worktree ? got_worktree_get_repo_path(worktree) : cwd,
9279 NULL((void *)0));
9280 if (error != NULL((void *)0))
9281 goto done;
9282 error = apply_unveil(got_repo_get_path(repo), 0,
9283 worktree ? got_worktree_get_root_path(worktree) : NULL((void *)0));
9284 if (error)
9285 goto done;
9286 error = list_backup_refs(
9287 GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX"refs/got/backup/histedit",
9288 argc == 1 ? argv[0] : NULL((void *)0), repo);
9289 goto done; /* nothing else to do */
9290 }
9291
9292 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
9293 NULL((void *)0));
9294 if (error != NULL((void *)0))
9295 goto done;
9296
9297 error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
9298 if (error)
9299 goto done;
9300 if (rebase_in_progress) {
9301 error = got_error(GOT_ERR_REBASING88);
9302 goto done;
9303 }
9304
9305 error = got_worktree_histedit_in_progress(&edit_in_progress, worktree);
9306 if (error)
9307 goto done;
9308
9309 if (edit_in_progress && edit_logmsg_only) {
9310 error = got_error_msg(GOT_ERR_HISTEDIT_BUSY96,
9311 "histedit operation is in progress in this "
9312 "work tree and must be continued or aborted "
9313 "before the -m option can be used");
9314 goto done;
9315 }
9316 if (edit_in_progress && fold_only) {
9317 error = got_error_msg(GOT_ERR_HISTEDIT_BUSY96,
9318 "histedit operation is in progress in this "
9319 "work tree and must be continued or aborted "
9320 "before the -f option can be used");
9321 goto done;
9322 }
9323
9324 if (edit_in_progress && abort_edit) {
9325 error = got_worktree_histedit_continue(&resume_commit_id,
9326 &tmp_branch, &branch, &base_commit_id, &fileindex,
9327 worktree, repo);
9328 if (error)
9329 goto done;
9330 printf("Switching work tree to %s\n",
9331 got_ref_get_symref_target(branch));
9332 error = got_worktree_histedit_abort(worktree, fileindex, repo,
9333 branch, base_commit_id, update_progress, &upa);
9334 if (error)
9335 goto done;
9336 printf("Histedit of %s aborted\n",
9337 got_ref_get_symref_target(branch));
9338 print_update_progress_stats(&upa);
9339 goto done; /* nothing else to do */
9340 } else if (abort_edit) {
9341 error = got_error(GOT_ERR_NOT_HISTEDIT90);
9342 goto done;
9343 }
9344
9345 if (continue_edit) {
9346 char *path;
9347
9348 if (!edit_in_progress) {
9349 error = got_error(GOT_ERR_NOT_HISTEDIT90);
9350 goto done;
9351 }
9352
9353 error = got_worktree_get_histedit_script_path(&path, worktree);
9354 if (error)
9355 goto done;
9356
9357 error = histedit_load_list(&histedit_cmds, path, repo);
9358 free(path);
9359 if (error)
9360 goto done;
9361
9362 error = got_worktree_histedit_continue(&resume_commit_id,
9363 &tmp_branch, &branch, &base_commit_id, &fileindex,
9364 worktree, repo);
9365 if (error)
9366 goto done;
9367
9368 error = got_ref_resolve(&head_commit_id, repo, branch);
9369 if (error)
9370 goto done;
9371
9372 error = got_object_open_as_commit(&commit, repo,
9373 head_commit_id);
9374 if (error)
9375 goto done;
9376 parent_ids = got_object_commit_get_parent_ids(commit);
9377 pid = SIMPLEQ_FIRST(parent_ids)((parent_ids)->sqh_first);
9378 if (pid == NULL((void *)0)) {
9379 error = got_error(GOT_ERR_EMPTY_HISTEDIT91);
9380 goto done;
9381 }
9382 error = collect_commits(&commits, head_commit_id, pid->id,
9383 base_commit_id, got_worktree_get_path_prefix(worktree),
9384 GOT_ERR_HISTEDIT_PATH98, repo);
9385 got_object_commit_close(commit);
9386 commit = NULL((void *)0);
9387 if (error)
9388 goto done;
9389 } else {
9390 if (edit_in_progress) {
9391 error = got_error(GOT_ERR_HISTEDIT_BUSY96);
9392 goto done;
9393 }
9394
9395 error = got_ref_open(&branch, repo,
9396 got_worktree_get_head_ref_name(worktree), 0);
9397 if (error != NULL((void *)0))
9398 goto done;
9399
9400 if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
9401 error = got_error_msg(GOT_ERR_COMMIT_BRANCH100,
9402 "will not edit commit history of a branch outside "
9403 "the \"refs/heads/\" reference namespace");
9404 goto done;
9405 }
9406
9407 error = got_ref_resolve(&head_commit_id, repo, branch);
9408 got_ref_close(branch);
9409 branch = NULL((void *)0);
9410 if (error)
9411 goto done;
9412
9413 error = got_object_open_as_commit(&commit, repo,
9414 head_commit_id);
9415 if (error)
9416 goto done;
9417 parent_ids = got_object_commit_get_parent_ids(commit);
9418 pid = SIMPLEQ_FIRST(parent_ids)((parent_ids)->sqh_first);
9419 if (pid == NULL((void *)0)) {
9420 error = got_error(GOT_ERR_EMPTY_HISTEDIT91);
9421 goto done;
9422 }
9423 error = collect_commits(&commits, head_commit_id, pid->id,
9424 got_worktree_get_base_commit_id(worktree),
9425 got_worktree_get_path_prefix(worktree),
9426 GOT_ERR_HISTEDIT_PATH98, repo);
9427 got_object_commit_close(commit);
9428 commit = NULL((void *)0);
9429 if (error)
9430 goto done;
9431
9432 if (SIMPLEQ_EMPTY(&commits)(((&commits)->sqh_first) == ((void *)0))) {
9433 error = got_error(GOT_ERR_EMPTY_HISTEDIT91);
9434 goto done;
9435 }
9436
9437 error = got_worktree_histedit_prepare(&tmp_branch, &branch,
9438 &base_commit_id, &fileindex, worktree, repo);
9439 if (error)
9440 goto done;
9441
9442 if (edit_script_path) {
9443 error = histedit_load_list(&histedit_cmds,
9444 edit_script_path, repo);
9445 if (error) {
9446 got_worktree_histedit_abort(worktree, fileindex,
9447 repo, branch, base_commit_id,
9448 update_progress, &upa);
9449 print_update_progress_stats(&upa);
9450 goto done;
9451 }
9452 } else {
9453 const char *branch_name;
9454 branch_name = got_ref_get_symref_target(branch);
9455 if (strncmp(branch_name, "refs/heads/", 11) == 0)
9456 branch_name += 11;
9457 error = histedit_edit_script(&histedit_cmds, &commits,
9458 branch_name, edit_logmsg_only, fold_only, repo);
9459 if (error) {
9460 got_worktree_histedit_abort(worktree, fileindex,
9461 repo, branch, base_commit_id,
9462 update_progress, &upa);
9463 print_update_progress_stats(&upa);
9464 goto done;
9465 }
9466
9467 }
9468
9469 error = histedit_save_list(&histedit_cmds, worktree,
9470 repo);
9471 if (error) {
9472 got_worktree_histedit_abort(worktree, fileindex,
9473 repo, branch, base_commit_id,
9474 update_progress, &upa);
9475 print_update_progress_stats(&upa);
9476 goto done;
9477 }
9478
9479 }
9480
9481 error = histedit_check_script(&histedit_cmds, &commits, repo);
9482 if (error)
9483 goto done;
9484
9485 TAILQ_FOREACH(hle, &histedit_cmds, entry)for((hle) = ((&histedit_cmds)->tqh_first); (hle) != ((
void *)0); (hle) = ((hle)->entry.tqe_next))
{
9486 if (resume_commit_id) {
9487 if (got_object_id_cmp(hle->commit_id,
9488 resume_commit_id) != 0)
9489 continue;
9490
9491 resume_commit_id = NULL((void *)0);
9492 if (hle->cmd->code == GOT_HISTEDIT_DROP'd' ||
9493 hle->cmd->code == GOT_HISTEDIT_FOLD'f') {
9494 error = histedit_skip_commit(hle, worktree,
9495 repo);
9496 if (error)
9497 goto done;
9498 } else {
9499 struct got_pathlist_head paths;
9500 int have_changes = 0;
9501
9502 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
9503 error = got_pathlist_append(&paths, "", NULL((void *)0));
9504 if (error)
9505 goto done;
9506 error = got_worktree_status(worktree, &paths,
9507 repo, check_local_changes, &have_changes,
9508 check_cancelled, NULL((void *)0));
9509 got_pathlist_free(&paths);
9510 if (error) {
9511 if (error->code != GOT_ERR_CANCELLED49)
9512 goto done;
9513 if (sigint_received || sigpipe_received)
9514 goto done;
9515 }
9516 if (have_changes) {
9517 error = histedit_commit(NULL((void *)0), worktree,
9518 fileindex, tmp_branch, hle, repo);
9519 if (error)
9520 goto done;
9521 } else {
9522 error = got_object_open_as_commit(
9523 &commit, repo, hle->commit_id);
9524 if (error)
9525 goto done;
9526 error = show_histedit_progress(commit,
9527 hle, NULL((void *)0));
9528 got_object_commit_close(commit);
9529 commit = NULL((void *)0);
9530 if (error)
9531 goto done;
9532 }
9533 }
9534 continue;
9535 }
9536
9537 if (hle->cmd->code == GOT_HISTEDIT_DROP'd') {
9538 error = histedit_skip_commit(hle, worktree, repo);
9539 if (error)
9540 goto done;
9541 continue;
9542 }
9543
9544 error = got_object_open_as_commit(&commit, repo,
9545 hle->commit_id);
9546 if (error)
9547 goto done;
9548 parent_ids = got_object_commit_get_parent_ids(commit);
9549 pid = SIMPLEQ_FIRST(parent_ids)((parent_ids)->sqh_first);
9550
9551 error = got_worktree_histedit_merge_files(&merged_paths,
9552 worktree, fileindex, pid->id, hle->commit_id, repo,
9553 update_progress, &upa, check_cancelled, NULL((void *)0));
9554 if (error)
9555 goto done;
9556 got_object_commit_close(commit);
9557 commit = NULL((void *)0);
9558
9559 print_update_progress_stats(&upa);
9560 if (upa.conflicts > 0)
9561 rebase_status = GOT_STATUS_CONFLICT'C';
9562
9563 if (rebase_status == GOT_STATUS_CONFLICT'C') {
9564 error = show_rebase_merge_conflict(hle->commit_id,
9565 repo);
9566 if (error)
9567 goto done;
9568 got_worktree_rebase_pathlist_free(&merged_paths);
9569 break;
9570 }
9571
9572 if (hle->cmd->code == GOT_HISTEDIT_EDIT'e') {
9573 char *id_str;
9574 error = got_object_id_str(&id_str, hle->commit_id);
9575 if (error)
9576 goto done;
9577 printf("Stopping histedit for amending commit %s\n",
9578 id_str);
9579 free(id_str);
9580 got_worktree_rebase_pathlist_free(&merged_paths);
9581 error = got_worktree_histedit_postpone(worktree,
9582 fileindex);
9583 goto done;
9584 }
9585
9586 if (hle->cmd->code == GOT_HISTEDIT_FOLD'f') {
9587 error = histedit_skip_commit(hle, worktree, repo);
9588 if (error)
9589 goto done;
9590 continue;
9591 }
9592
9593 error = histedit_commit(&merged_paths, worktree, fileindex,
9594 tmp_branch, hle, repo);
9595 got_worktree_rebase_pathlist_free(&merged_paths);
9596 if (error)
9597 goto done;
9598 }
9599
9600 if (rebase_status == GOT_STATUS_CONFLICT'C') {
9601 error = got_worktree_histedit_postpone(worktree, fileindex);
9602 if (error)
9603 goto done;
9604 error = got_error_msg(GOT_ERR_CONFLICTS82,
9605 "conflicts must be resolved before histedit can continue");
9606 } else
9607 error = histedit_complete(worktree, fileindex, tmp_branch,
9608 branch, repo);
9609done:
9610 got_object_id_queue_free(&commits);
9611 histedit_free_list(&histedit_cmds);
9612 free(head_commit_id);
9613 free(base_commit_id);
9614 free(resume_commit_id);
9615 if (commit)
9616 got_object_commit_close(commit);
9617 if (branch)
9618 got_ref_close(branch);
9619 if (tmp_branch)
9620 got_ref_close(tmp_branch);
9621 if (worktree)
9622 got_worktree_close(worktree);
9623 if (repo)
9624 got_repo_close(repo);
9625 return error;
9626}
9627
9628__dead__attribute__((__noreturn__)) static void
9629usage_integrate(void)
9630{
9631 fprintf(stderr(&__sF[2]), "usage: %s integrate branch\n", getprogname());
9632 exit(1);
9633}
9634
9635static const struct got_error *
9636cmd_integrate(int argc, char *argv[])
9637{
9638 const struct got_error *error = NULL((void *)0);
9639 struct got_repository *repo = NULL((void *)0);
9640 struct got_worktree *worktree = NULL((void *)0);
9641 char *cwd = NULL((void *)0), *refname = NULL((void *)0), *base_refname = NULL((void *)0);
9642 const char *branch_arg = NULL((void *)0);
9643 struct got_reference *branch_ref = NULL((void *)0), *base_branch_ref = NULL((void *)0);
9644 struct got_fileindex *fileindex = NULL((void *)0);
9645 struct got_object_id *commit_id = NULL((void *)0), *base_commit_id = NULL((void *)0);
9646 int ch;
9647 struct got_update_progress_arg upa;
9648
9649 while ((ch = getopt(argc, argv, "")) != -1) {
9650 switch (ch) {
9651 default:
9652 usage_integrate();
9653 /* NOTREACHED */
9654 }
9655 }
9656
9657 argc -= optind;
9658 argv += optind;
9659
9660 if (argc != 1)
9661 usage_integrate();
9662 branch_arg = argv[0];
9663#ifndef PROFILE
9664 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9665 "unveil", NULL((void *)0)) == -1)
9666 err(1, "pledge");
9667#endif
9668 cwd = getcwd(NULL((void *)0), 0);
9669 if (cwd == NULL((void *)0)) {
9670 error = got_error_from_errno("getcwd");
9671 goto done;
9672 }
9673
9674 error = got_worktree_open(&worktree, cwd);
9675 if (error) {
9676 if (error->code == GOT_ERR_NOT_WORKTREE60)
9677 error = wrap_not_worktree_error(error, "integrate",
9678 cwd);
9679 goto done;
9680 }
9681
9682 error = check_rebase_or_histedit_in_progress(worktree);
9683 if (error)
9684 goto done;
9685
9686 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
9687 NULL((void *)0));
9688 if (error != NULL((void *)0))
9689 goto done;
9690
9691 error = apply_unveil(got_repo_get_path(repo), 0,
9692 got_worktree_get_root_path(worktree));
9693 if (error)
9694 goto done;
9695
9696 if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
9697 error = got_error_from_errno("asprintf");
9698 goto done;
9699 }
9700
9701 error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
9702 &base_branch_ref, worktree, refname, repo);
9703 if (error)
9704 goto done;
9705
9706 refname = strdup(got_ref_get_name(branch_ref));
9707 if (refname == NULL((void *)0)) {
9708 error = got_error_from_errno("strdup");
9709 got_worktree_integrate_abort(worktree, fileindex, repo,
9710 branch_ref, base_branch_ref);
9711 goto done;
9712 }
9713 base_refname = strdup(got_ref_get_name(base_branch_ref));
9714 if (base_refname == NULL((void *)0)) {
9715 error = got_error_from_errno("strdup");
9716 got_worktree_integrate_abort(worktree, fileindex, repo,
9717 branch_ref, base_branch_ref);
9718 goto done;
9719 }
9720
9721 error = got_ref_resolve(&commit_id, repo, branch_ref);
9722 if (error)
9723 goto done;
9724
9725 error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
9726 if (error)
9727 goto done;
9728
9729 if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
9730 error = got_error_msg(GOT_ERR_SAME_BRANCH79,
9731 "specified branch has already been integrated");
9732 got_worktree_integrate_abort(worktree, fileindex, repo,
9733 branch_ref, base_branch_ref);
9734 goto done;
9735 }
9736
9737 error = check_linear_ancestry(commit_id, base_commit_id, 1, repo);
9738 if (error) {
9739 if (error->code == GOT_ERR_ANCESTRY55)
9740 error = got_error(GOT_ERR_REBASE_REQUIRED111);
9741 got_worktree_integrate_abort(worktree, fileindex, repo,
9742 branch_ref, base_branch_ref);
9743 goto done;
9744 }
9745
9746 memset(&upa, 0, sizeof(upa));
9747 error = got_worktree_integrate_continue(worktree, fileindex, repo,
9748 branch_ref, base_branch_ref, update_progress, &upa,
9749 check_cancelled, NULL((void *)0));
9750 if (error)
9751 goto done;
9752
9753 printf("Integrated %s into %s\n", refname, base_refname);
9754 print_update_progress_stats(&upa);
9755done:
9756 if (repo)
9757 got_repo_close(repo);
9758 if (worktree)
9759 got_worktree_close(worktree);
9760 free(cwd);
9761 free(base_commit_id);
9762 free(commit_id);
9763 free(refname);
9764 free(base_refname);
9765 return error;
9766}
9767
9768__dead__attribute__((__noreturn__)) static void
9769usage_stage(void)
9770{
9771 fprintf(stderr(&__sF[2]), "usage: %s stage [-l] | [-p] [-F response-script] "
9772 "[-S] [file-path ...]\n",
9773 getprogname());
9774 exit(1);
9775}
9776
9777static const struct got_error *
9778print_stage(void *arg, unsigned char status, unsigned char staged_status,
9779 const char *path, struct got_object_id *blob_id,
9780 struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
9781 int dirfd, const char *de_name)
9782{
9783 const struct got_error *err = NULL((void *)0);
9784 char *id_str = NULL((void *)0);
9785
9786 if (staged_status != GOT_STATUS_ADD'A' &&
9787 staged_status != GOT_STATUS_MODIFY'M' &&
9788 staged_status != GOT_STATUS_DELETE'D')
9789 return NULL((void *)0);
9790
9791 if (staged_status == GOT_STATUS_ADD'A' ||
9792 staged_status == GOT_STATUS_MODIFY'M')
9793 err = got_object_id_str(&id_str, staged_blob_id);
9794 else
9795 err = got_object_id_str(&id_str, blob_id);
9796 if (err)
9797 return err;
9798
9799 printf("%s %c %s\n", id_str, staged_status, path);
9800 free(id_str);
9801 return NULL((void *)0);
9802}
9803
9804static const struct got_error *
9805cmd_stage(int argc, char *argv[])
9806{
9807 const struct got_error *error = NULL((void *)0);
9808 struct got_repository *repo = NULL((void *)0);
9809 struct got_worktree *worktree = NULL((void *)0);
9810 char *cwd = NULL((void *)0);
9811 struct got_pathlist_head paths;
9812 struct got_pathlist_entry *pe;
9813 int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0;
9814 FILE *patch_script_file = NULL((void *)0);
9815 const char *patch_script_path = NULL((void *)0);
9816 struct choose_patch_arg cpa;
9817
9818 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
9819
9820 while ((ch = getopt(argc, argv, "lpF:S")) != -1) {
9821 switch (ch) {
9822 case 'l':
9823 list_stage = 1;
9824 break;
9825 case 'p':
9826 pflag = 1;
9827 break;
9828 case 'F':
9829 patch_script_path = optarg;
9830 break;
9831 case 'S':
9832 allow_bad_symlinks = 1;
9833 break;
9834 default:
9835 usage_stage();
9836 /* NOTREACHED */
9837 }
9838 }
9839
9840 argc -= optind;
9841 argv += optind;
9842
9843#ifndef PROFILE
9844 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9845 "unveil", NULL((void *)0)) == -1)
9846 err(1, "pledge");
9847#endif
9848 if (list_stage && (pflag || patch_script_path))
9849 errx(1, "-l option cannot be used with other options");
9850 if (patch_script_path && !pflag)
9851 errx(1, "-F option can only be used together with -p option");
9852
9853 cwd = getcwd(NULL((void *)0), 0);
9854 if (cwd == NULL((void *)0)) {
9855 error = got_error_from_errno("getcwd");
9856 goto done;
9857 }
9858
9859 error = got_worktree_open(&worktree, cwd);
9860 if (error) {
9861 if (error->code == GOT_ERR_NOT_WORKTREE60)
9862 error = wrap_not_worktree_error(error, "stage", cwd);
9863 goto done;
9864 }
9865
9866 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
9867 NULL((void *)0));
9868 if (error != NULL((void *)0))
9869 goto done;
9870
9871 if (patch_script_path) {
9872 patch_script_file = fopen(patch_script_path, "r");
9873 if (patch_script_file == NULL((void *)0)) {
9874 error = got_error_from_errno2("fopen",
9875 patch_script_path);
9876 goto done;
9877 }
9878 }
9879 error = apply_unveil(got_repo_get_path(repo), 0,
9880 got_worktree_get_root_path(worktree));
9881 if (error)
9882 goto done;
9883
9884 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
9885 if (error)
9886 goto done;
9887
9888 if (list_stage)
9889 error = got_worktree_status(worktree, &paths, repo,
9890 print_stage, NULL((void *)0), check_cancelled, NULL((void *)0));
9891 else {
9892 cpa.patch_script_file = patch_script_file;
9893 cpa.action = "stage";
9894 error = got_worktree_stage(worktree, &paths,
9895 pflag ? NULL((void *)0) : print_status, NULL((void *)0),
9896 pflag ? choose_patch : NULL((void *)0), &cpa,
9897 allow_bad_symlinks, repo);
9898 }
9899done:
9900 if (patch_script_file && fclose(patch_script_file) == EOF(-1) &&
9901 error == NULL((void *)0))
9902 error = got_error_from_errno2("fclose", patch_script_path);
9903 if (repo)
9904 got_repo_close(repo);
9905 if (worktree)
9906 got_worktree_close(worktree);
9907 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
9908 free((char *)pe->path);
9909 got_pathlist_free(&paths);
9910 free(cwd);
9911 return error;
9912}
9913
9914__dead__attribute__((__noreturn__)) static void
9915usage_unstage(void)
9916{
9917 fprintf(stderr(&__sF[2]), "usage: %s unstage [-p] [-F response-script] "
9918 "[file-path ...]\n",
9919 getprogname());
9920 exit(1);
9921}
9922
9923
9924static const struct got_error *
9925cmd_unstage(int argc, char *argv[])
9926{
9927 const struct got_error *error = NULL((void *)0);
9928 struct got_repository *repo = NULL((void *)0);
9929 struct got_worktree *worktree = NULL((void *)0);
9930 char *cwd = NULL((void *)0);
9931 struct got_pathlist_head paths;
9932 struct got_pathlist_entry *pe;
9933 int ch, pflag = 0;
9934 struct got_update_progress_arg upa;
9935 FILE *patch_script_file = NULL((void *)0);
9936 const char *patch_script_path = NULL((void *)0);
9937 struct choose_patch_arg cpa;
9938
9939 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
9940
9941 while ((ch = getopt(argc, argv, "pF:")) != -1) {
9942 switch (ch) {
9943 case 'p':
9944 pflag = 1;
9945 break;
9946 case 'F':
9947 patch_script_path = optarg;
9948 break;
9949 default:
9950 usage_unstage();
9951 /* NOTREACHED */
9952 }
9953 }
9954
9955 argc -= optind;
9956 argv += optind;
9957
9958#ifndef PROFILE
9959 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9960 "unveil", NULL((void *)0)) == -1)
9961 err(1, "pledge");
9962#endif
9963 if (patch_script_path && !pflag)
9964 errx(1, "-F option can only be used together with -p option");
9965
9966 cwd = getcwd(NULL((void *)0), 0);
9967 if (cwd == NULL((void *)0)) {
9968 error = got_error_from_errno("getcwd");
9969 goto done;
9970 }
9971
9972 error = got_worktree_open(&worktree, cwd);
9973 if (error) {
9974 if (error->code == GOT_ERR_NOT_WORKTREE60)
9975 error = wrap_not_worktree_error(error, "unstage", cwd);
9976 goto done;
9977 }
9978
9979 error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
9980 NULL((void *)0));
9981 if (error != NULL((void *)0))
9982 goto done;
9983
9984 if (patch_script_path) {
9985 patch_script_file = fopen(patch_script_path, "r");
9986 if (patch_script_file == NULL((void *)0)) {
9987 error = got_error_from_errno2("fopen",
9988 patch_script_path);
9989 goto done;
9990 }
9991 }
9992
9993 error = apply_unveil(got_repo_get_path(repo), 0,
9994 got_worktree_get_root_path(worktree));
9995 if (error)
9996 goto done;
9997
9998 error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
9999 if (error)
10000 goto done;
10001
10002 cpa.patch_script_file = patch_script_file;
10003 cpa.action = "unstage";
10004 memset(&upa, 0, sizeof(upa));
10005 error = got_worktree_unstage(worktree, &paths, update_progress,
10006 &upa, pflag ? choose_patch : NULL((void *)0), &cpa, repo);
10007 if (!error)
10008 print_update_progress_stats(&upa);
10009done:
10010 if (patch_script_file && fclose(patch_script_file) == EOF(-1) &&
10011 error == NULL((void *)0))
10012 error = got_error_from_errno2("fclose", patch_script_path);
10013 if (repo)
10014 got_repo_close(repo);
10015 if (worktree)
10016 got_worktree_close(worktree);
10017 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
10018 free((char *)pe->path);
10019 got_pathlist_free(&paths);
10020 free(cwd);
10021 return error;
10022}
10023
10024__dead__attribute__((__noreturn__)) static void
10025usage_cat(void)
10026{
10027 fprintf(stderr(&__sF[2]), "usage: %s cat [-r repository ] [ -c commit ] [ -P ] "
10028 "arg1 [arg2 ...]\n", getprogname());
10029 exit(1);
10030}
10031
10032static const struct got_error *
10033cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
10034{
10035 const struct got_error *err;
10036 struct got_blob_object *blob;
10037
10038 err = got_object_open_as_blob(&blob, repo, id, 8192);
10039 if (err)
10040 return err;
10041
10042 err = got_object_blob_dump_to_file(NULL((void *)0), NULL((void *)0), NULL((void *)0), outfile, blob);
10043 got_object_blob_close(blob);
10044 return err;
10045}
10046
10047static const struct got_error *
10048cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
10049{
10050 const struct got_error *err;
10051 struct got_tree_object *tree;
10052 int nentries, i;
10053
10054 err = got_object_open_as_tree(&tree, repo, id);
10055 if (err)
10056 return err;
10057
10058 nentries = got_object_tree_get_nentries(tree);
10059 for (i = 0; i < nentries; i++) {
10060 struct got_tree_entry *te;
10061 char *id_str;
10062 if (sigint_received || sigpipe_received)
10063 break;
10064 te = got_object_tree_get_entry(tree, i);
10065 err = got_object_id_str(&id_str, got_tree_entry_get_id(te));
10066 if (err)
10067 break;
10068 fprintf(outfile, "%s %.7o %s\n", id_str,
10069 got_tree_entry_get_mode(te),
10070 got_tree_entry_get_name(te));
10071 free(id_str);
10072 }
10073
10074 got_object_tree_close(tree);
10075 return err;
10076}
10077
10078static const struct got_error *
10079cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
10080{
10081 const struct got_error *err;
10082 struct got_commit_object *commit;
10083 const struct got_object_id_queue *parent_ids;
10084 struct got_object_qid *pid;
10085 char *id_str = NULL((void *)0);
10086 const char *logmsg = NULL((void *)0);
10087
10088 err = got_object_open_as_commit(&commit, repo, id);
10089 if (err)
10090 return err;
10091
10092 err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit));
10093 if (err)
10094 goto done;
10095
10096 fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE"tree ", id_str);
10097 parent_ids = got_object_commit_get_parent_ids(commit);
10098 fprintf(outfile, "numparents %d\n",
10099 got_object_commit_get_nparents(commit));
10100 SIMPLEQ_FOREACH(pid, parent_ids, entry)for((pid) = ((parent_ids)->sqh_first); (pid) != ((void *)0
); (pid) = ((pid)->entry.sqe_next))
{
10101 char *pid_str;
10102 err = got_object_id_str(&pid_str, pid->id);
10103 if (err)
10104 goto done;
10105 fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT"parent ", pid_str);
10106 free(pid_str);
10107 }
10108 fprintf(outfile, "%s%s %lld +0000\n", GOT_COMMIT_LABEL_AUTHOR"author ",
10109 got_object_commit_get_author(commit),
10110 (long long)got_object_commit_get_author_time(commit));
10111
10112 fprintf(outfile, "%s%s %lld +0000\n", GOT_COMMIT_LABEL_COMMITTER"committer ",
10113 got_object_commit_get_author(commit),
10114 (long long)got_object_commit_get_committer_time(commit));
10115
10116 logmsg = got_object_commit_get_logmsg_raw(commit);
10117 fprintf(outfile, "messagelen %zd\n", strlen(logmsg));
10118 fprintf(outfile, "%s", logmsg);
10119done:
10120 free(id_str);
10121 got_object_commit_close(commit);
10122 return err;
10123}
10124
10125static const struct got_error *
10126cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
10127{
10128 const struct got_error *err;
10129 struct got_tag_object *tag;
10130 char *id_str = NULL((void *)0);
10131 const char *tagmsg = NULL((void *)0);
10132
10133 err = got_object_open_as_tag(&tag, repo, id);
10134 if (err)
10135 return err;
10136
10137 err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag));
10138 if (err)
10139 goto done;
10140
10141 fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT"object ", id_str);
10142
10143 switch (got_object_tag_get_object_type(tag)) {
10144 case GOT_OBJ_TYPE_BLOB3:
10145 fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE"type ",
10146 GOT_OBJ_LABEL_BLOB"blob");
10147 break;
10148 case GOT_OBJ_TYPE_TREE2:
10149 fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE"type ",
10150 GOT_OBJ_LABEL_TREE"tree");
10151 break;
10152 case GOT_OBJ_TYPE_COMMIT1:
10153 fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE"type ",
10154 GOT_OBJ_LABEL_COMMIT"commit");
10155 break;
10156 case GOT_OBJ_TYPE_TAG4:
10157 fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE"type ",
10158 GOT_OBJ_LABEL_TAG"tag");
10159 break;
10160 default:
10161 break;
10162 }
10163
10164 fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG"tag ",
10165 got_object_tag_get_name(tag));
10166
10167 fprintf(outfile, "%s%s %lld +0000\n", GOT_TAG_LABEL_TAGGER"tagger ",
10168 got_object_tag_get_tagger(tag),
10169 (long long)got_object_tag_get_tagger_time(tag));
10170
10171 tagmsg = got_object_tag_get_message(tag);
10172 fprintf(outfile, "messagelen %zd\n", strlen(tagmsg));
10173 fprintf(outfile, "%s", tagmsg);
10174done:
10175 free(id_str);
10176 got_object_tag_close(tag);
10177 return err;
10178}
10179
10180static const struct got_error *
10181cmd_cat(int argc, char *argv[])
10182{
10183 const struct got_error *error;
10184 struct got_repository *repo = NULL((void *)0);
10185 struct got_worktree *worktree = NULL((void *)0);
10186 char *cwd = NULL((void *)0), *repo_path = NULL((void *)0), *label = NULL((void *)0);
10187 const char *commit_id_str = NULL((void *)0);
10188 struct got_object_id *id = NULL((void *)0), *commit_id = NULL((void *)0);
10189 int ch, obj_type, i, force_path = 0;
10190 struct got_reflist_head refs;
10191
10192 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
10193
10194#ifndef PROFILE
10195 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
10196 NULL((void *)0)) == -1)
10197 err(1, "pledge");
10198#endif
10199
10200 while ((ch = getopt(argc, argv, "c:r:P")) != -1) {
10201 switch (ch) {
10202 case 'c':
10203 commit_id_str = optarg;
10204 break;
10205 case 'r':
10206 repo_path = realpath(optarg, NULL((void *)0));
10207 if (repo_path == NULL((void *)0))
10208 return got_error_from_errno2("realpath",
10209 optarg);
10210 got_path_strip_trailing_slashes(repo_path);
10211 break;
10212 case 'P':
10213 force_path = 1;
10214 break;
10215 default:
10216 usage_cat();
10217 /* NOTREACHED */
10218 }
10219 }
10220
10221 argc -= optind;
10222 argv += optind;
10223
10224 cwd = getcwd(NULL((void *)0), 0);
10225 if (cwd == NULL((void *)0)) {
10226 error = got_error_from_errno("getcwd");
10227 goto done;
10228 }
10229 error = got_worktree_open(&worktree, cwd);
10230 if (error && error->code != GOT_ERR_NOT_WORKTREE60)
10231 goto done;
10232 if (worktree) {
10233 if (repo_path == NULL((void *)0)) {
10234 repo_path = strdup(
10235 got_worktree_get_repo_path(worktree));
10236 if (repo_path == NULL((void *)0)) {
10237 error = got_error_from_errno("strdup");
10238 goto done;
10239 }
10240 }
10241 }
10242
10243 if (repo_path == NULL((void *)0)) {
10244 repo_path = getcwd(NULL((void *)0), 0);
10245 if (repo_path == NULL((void *)0))
10246 return got_error_from_errno("getcwd");
10247 }
10248
10249 error = got_repo_open(&repo, repo_path, NULL((void *)0));
10250 free(repo_path);
10251 if (error != NULL((void *)0))
10252 goto done;
10253
10254 error = apply_unveil(got_repo_get_path(repo), 1, NULL((void *)0));
10255 if (error)
10256 goto done;
10257
10258 error = got_ref_list(&refs, repo, NULL((void *)0), got_ref_cmp_by_name, NULL((void *)0));
10259 if (error)
10260 goto done;
10261
10262 if (commit_id_str == NULL((void *)0))
10263 commit_id_str = GOT_REF_HEAD"HEAD";
10264 error = got_repo_match_object_id(&commit_id, NULL((void *)0),
10265 commit_id_str, GOT_OBJ_TYPE_COMMIT1, &refs, repo);
10266 if (error)
10267 goto done;
10268
10269 for (i = 0; i < argc; i++) {
10270 if (force_path) {
10271 error = got_object_id_by_path(&id, repo, commit_id,
10272 argv[i]);
10273 if (error)
10274 break;
10275 } else {
10276 error = got_repo_match_object_id(&id, &label, argv[i],
10277 GOT_OBJ_TYPE_ANY0, NULL((void *)0) /* do not resolve tags */,
10278 repo);
10279 if (error) {
10280 if (error->code != GOT_ERR_BAD_OBJ_ID_STR23 &&
10281 error->code != GOT_ERR_NOT_REF5)
10282 break;
10283 error = got_object_id_by_path(&id, repo,
10284 commit_id, argv[i]);
10285 if (error)
10286 break;
10287 }
10288 }
10289
10290 error = got_object_get_type(&obj_type, repo, id);
10291 if (error)
10292 break;
10293
10294 switch (obj_type) {
10295 case GOT_OBJ_TYPE_BLOB3:
10296 error = cat_blob(id, repo, stdout(&__sF[1]));
10297 break;
10298 case GOT_OBJ_TYPE_TREE2:
10299 error = cat_tree(id, repo, stdout(&__sF[1]));
10300 break;
10301 case GOT_OBJ_TYPE_COMMIT1:
10302 error = cat_commit(id, repo, stdout(&__sF[1]));
10303 break;
10304 case GOT_OBJ_TYPE_TAG4:
10305 error = cat_tag(id, repo, stdout(&__sF[1]));
10306 break;
10307 default:
10308 error = got_error(GOT_ERR_OBJ_TYPE11);
10309 break;
10310 }
10311 if (error)
10312 break;
10313 free(label);
10314 label = NULL((void *)0);
10315 free(id);
10316 id = NULL((void *)0);
10317 }
10318done:
10319 free(label);
10320 free(id);
10321 free(commit_id);
10322 if (worktree)
10323 got_worktree_close(worktree);
10324 if (repo) {
10325 const struct got_error *repo_error;
10326 repo_error = got_repo_close(repo);
10327 if (error == NULL((void *)0))
10328 error = repo_error;
10329 }
10330 got_ref_list_free(&refs);
10331 return error;
10332}
10333
10334__dead__attribute__((__noreturn__)) static void
10335usage_info(void)
10336{
10337 fprintf(stderr(&__sF[2]), "usage: %s info [path ...]\n",
10338 getprogname());
10339 exit(1);
10340}
10341
10342static const struct got_error *
10343print_path_info(void *arg, const char *path, mode_t mode, time_t mtime,
10344 struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
10345 struct got_object_id *commit_id)
10346{
10347 const struct got_error *err = NULL((void *)0);
10348 char *id_str = NULL((void *)0);
10349 char datebuf[128];
10350 struct tm mytm, *tm;
10351 struct got_pathlist_head *paths = arg;
10352 struct got_pathlist_entry *pe;
10353
10354 /*
10355 * Clear error indication from any of the path arguments which
10356 * would cause this file index entry to be displayed.
10357 */
10358 TAILQ_FOREACH(pe, paths, entry)for((pe) = ((paths)->tqh_first); (pe) != ((void *)0); (pe)
= ((pe)->entry.tqe_next))
{
10359 if (got_path_cmp(path, pe->path, strlen(path),
10360 pe->path_len) == 0 ||
10361 got_path_is_child(path, pe->path, pe->path_len))
10362 pe->data = NULL((void *)0); /* no error */
10363 }
10364
10365 printf(GOT_COMMIT_SEP_STR"-----------------------------------------------\n");
10366 if (S_ISLNK(mode)((mode & 0170000) == 0120000))
10367 printf("symlink: %s\n", path);
10368 else if (S_ISREG(mode)((mode & 0170000) == 0100000)) {
10369 printf("file: %s\n", path);
10370 printf("mode: %o\n", mode & (S_IRWXU0000700 | S_IRWXG0000070 | S_IRWXO0000007));
10371 } else if (S_ISDIR(mode)((mode & 0170000) == 0040000))
10372 printf("directory: %s\n", path);
10373 else
10374 printf("something: %s\n", path);
10375
10376 tm = localtime_r(&mtime, &mytm);
10377 if (tm == NULL((void *)0))
10378 return NULL((void *)0);
10379 if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0)
10380 return got_error(GOT_ERR_NO_SPACE9);
10381 printf("timestamp: %s\n", datebuf);
10382
10383 if (blob_id) {
10384 err = got_object_id_str(&id_str, blob_id);
10385 if (err)
10386 return err;
10387 printf("based on blob: %s\n", id_str);
10388 free(id_str);
10389 }
10390
10391 if (staged_blob_id) {
10392 err = got_object_id_str(&id_str, staged_blob_id);
10393 if (err)
10394 return err;
10395 printf("based on staged blob: %s\n", id_str);
10396 free(id_str);
10397 }
10398
10399 if (commit_id) {
10400 err = got_object_id_str(&id_str, commit_id);
10401 if (err)
10402 return err;
10403 printf("based on commit: %s\n", id_str);
10404 free(id_str);
10405 }
10406
10407 return NULL((void *)0);
10408}
10409
10410static const struct got_error *
10411cmd_info(int argc, char *argv[])
10412{
10413 const struct got_error *error = NULL((void *)0);
10414 struct got_worktree *worktree = NULL((void *)0);
10415 char *cwd = NULL((void *)0), *id_str = NULL((void *)0);
10416 struct got_pathlist_head paths;
10417 struct got_pathlist_entry *pe;
10418 char *uuidstr = NULL((void *)0);
10419 int ch, show_files = 0;
10420
10421 TAILQ_INIT(&paths)do { (&paths)->tqh_first = ((void *)0); (&paths)->
tqh_last = &(&paths)->tqh_first; } while (0)
;
10422
10423 while ((ch = getopt(argc, argv, "")) != -1) {
10424 switch (ch) {
10425 default:
10426 usage_info();
10427 /* NOTREACHED */
10428 }
10429 }
10430
10431 argc -= optind;
10432 argv += optind;
10433
10434#ifndef PROFILE
10435 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
10436 NULL((void *)0)) == -1)
10437 err(1, "pledge");
10438#endif
10439 cwd = getcwd(NULL((void *)0), 0);
10440 if (cwd == NULL((void *)0)) {
10441 error = got_error_from_errno("getcwd");
10442 goto done;
10443 }
10444
10445 error = got_worktree_open(&worktree, cwd);
10446 if (error) {
10447 if (error->code == GOT_ERR_NOT_WORKTREE60)
10448 error = wrap_not_worktree_error(error, "info", cwd);
10449 goto done;
10450 }
10451
10452 error = apply_unveil(NULL((void *)0), 0, got_worktree_get_root_path(worktree));
10453 if (error)
10454 goto done;
10455
10456 if (argc >= 1) {
10457 error = get_worktree_paths_from_argv(&paths, argc, argv,
10458 worktree);
10459 if (error)
10460 goto done;
10461 show_files = 1;
10462 }
10463
10464 error = got_object_id_str(&id_str,
10465 got_worktree_get_base_commit_id(worktree));
10466 if (error)
10467 goto done;
10468
10469 error = got_worktree_get_uuid(&uuidstr, worktree);
10470 if (error)
10471 goto done;
10472
10473 printf("work tree: %s\n", got_worktree_get_root_path(worktree));
10474 printf("work tree base commit: %s\n", id_str);
10475 printf("work tree path prefix: %s\n",
10476 got_worktree_get_path_prefix(worktree));
10477 printf("work tree branch reference: %s\n",
10478 got_worktree_get_head_ref_name(worktree));
10479 printf("work tree UUID: %s\n", uuidstr);
10480 printf("repository: %s\n", got_worktree_get_repo_path(worktree));
10481
10482 if (show_files) {
10483 struct got_pathlist_entry *pe;
10484 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
{
10485 if (pe->path_len == 0)
10486 continue;
10487 /*
10488 * Assume this path will fail. This will be corrected
10489 * in print_path_info() in case the path does suceeed.
10490 */
10491 pe->data = (void *)got_error_path(pe->path,
10492 GOT_ERR_BAD_PATH4);
10493 }
10494 error = got_worktree_path_info(worktree, &paths,
10495 print_path_info, &paths, check_cancelled, NULL((void *)0));
10496 if (error)
10497 goto done;
10498 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
{
10499 if (pe->data != NULL((void *)0)) {
10500 error = pe->data; /* bad path */
10501 break;
10502 }
10503 }
10504 }
10505done:
10506 TAILQ_FOREACH(pe, &paths, entry)for((pe) = ((&paths)->tqh_first); (pe) != ((void *)0);
(pe) = ((pe)->entry.tqe_next))
10507 free((char *)pe->path);
10508 got_pathlist_free(&paths);
10509 free(cwd);
10510 free(id_str);
10511 free(uuidstr);
10512 return error;
10513}