diff --git a/Makefile b/Makefile index 633f9a98..a601385e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SUBDIR = openbsd-compat libexec got tog +SUBDIR = openbsd-compat libexec got #tog .PHONY: release dist diff --git a/Makefile.inc b/Makefile.inc index 75319d1d..c9f17d23 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -8,6 +8,7 @@ CFLAGS += ${CPPFLAGS} -I${OPENBSD_COMPAT} CFLAGS += -Wno-pointer-sign LDADD += -lopenbsd-compat +LDADD += -lnv LIBADD += md WARNS = 0 diff --git a/got-notes b/got-notes new file mode 100644 index 00000000..7e4bbfac --- /dev/null +++ b/got-notes @@ -0,0 +1,176 @@ +function naming: got_path_mkdir() inside /got/lib/path.c + +In each cmd_X function in got.c, the structure is: + +parse options +pledge something +do some more setup +run apply_unveil +call function that actually does work (does not contain pledge or unveil) + +Apply_unveil: +gmon.out, rwc +repo_path, repo_read_only ? r : rwc +worktree_path, rwc +tmpdir, rwc +got_privsep_unveil_exec_helpers -> unveils helper programs in libexec with x +-> currently they use fork, exec to run the read helpers (for security) +-> replace these with a fileargs, then fork + fexecve + +path.c +-> simple approach, like in sort.c, where we have global fds that functions + use openat to use can't work here. Contains two kinds of functions: ones + that take in a path and open it and do stuff, and ones that take in a path + and does string manipulation. We can change the former to take in fds + instead, perhaps. +-> consider making alt functions like got_path_mkdir() => got_path_mkdirat() + +GOT_LIBEXECDIR - tells got where the libexec files are. I'll have to point this +somewhere else for now, by setting the env variable, and change it back later + +repo.c +-> write_tree mutually recursive with import_subdir - makes sense + +got_repo_import +-> want one file descriptor, the base to-be-imported directory. Rest controlled +with relative paths + +" +Got's high-level repo_open and worktree_open operations should be able +to accommodate file descriptors for relevant directories. Do not be afraid +of changing APIs anywhere in the Got tree if it helps. None of the APIs are +considered stable yet, not even those in the public include/ directory. + +The work tree status walk has already been partly converted to openat() +and friends, and there is some work left to do here. +My idea was to ensure that Got commands which are in progress will not +operate on new versions of files or directories that happen to be replaced +by third party tools while Got is operating on the work tree. +So instead of traversing directories by path, we traverse directory entry +names associated with a directory file descriptor. +" + +After fexecve finishes, all memory allocated to the process is discarded, +so you don't have to worry about memory leaks when making the argv to call +fexecve. + +Current exec_child strategy: make an nvlist of paths and fds, and initialize +it in the init function. Do a lookup for executing. Also, we need to call the +dynamic linker instead of the actual program: ld-elf.so.1. Look at the +Capsicumizer to see how they do it. Also, LD_LIBRARY_PATH_FDS for loading +the necessary libraries. Ed says loading /lib/ and /usr/lib/ is good enough. + +issue: exec_child not executing child right if kern.trap_enotcap is set. +If I add an infinite loop to the libexec, running it with the trap=0 hangs +the program, but it just says "peer process closed pipe" with trap=1, showing +that the program isn't even being run. There must be some sort of include +issue, or maybe the linker has a bug? + +The linker looks at config files. I don't really know if it's fixable... +turn on LD_DEBUG in the environment to look at it. + +I'm trying to fexecve a statically linked program now, and I get a similar problem - +it still doesn't manage to get into the program if kern.trap_enotcap=1. +I looked at the core dump and the issue seems to be in jemalloc: + +* thread #1, name = 'got-read-object', stop reason = signal SIGTRAP + * frame #0: 0x000000000027f08a got-read-object`__sys_readlink at readlink.S:4 + frame #1: 0x000000000027afeb got-read-object`malloc_conf_init_helper at jemalloc_jemalloc.c:984:13 + frame #2: 0x000000000027afd1 got-read-object`malloc_conf_init_helper(sc_data=0x0000000000000000, bin_shard_sizes=0x0000000000000000, initial_call=true, opts_cache=0x00007fffffffe800, buf=) at jemalloc_jemalloc.c:1042 + frame #3: 0x000000000027aa79 got-read-object`malloc_init_hard_a0_locked [inlined] malloc_conf_init(sc_data=0x00007fffffffca40, bin_shard_sizes=0x00007fffffffc9b0) at jemalloc_jemalloc.c:1449:2 + frame #4: 0x000000000027aa4f got-read-object`malloc_init_hard_a0_locked at jemalloc_jemalloc.c:1509 + frame #5: 0x0000000000273528 got-read-object`a0ialloc [inlined] malloc_init_hard_a0 at jemalloc_jemalloc.c:1572:8 + frame #6: 0x00000000002734d6 got-read-object`a0ialloc [inlined] malloc_init_a0 at jemalloc_jemalloc.c:220 + frame #7: 0x00000000002734d6 got-read-object`a0ialloc(size=6303, zero=false, is_internal=false) at jemalloc_jemalloc.c:240 + frame #8: 0x000000000024c06e got-read-object`__libc_allocate_tls [inlined] malloc_aligned(size=6280, align=16) at tls.c:134:8 + frame #9: 0x000000000024c054 got-read-object`__libc_allocate_tls(oldtls=0x0000000000000000, tcbsize=, tcbalign=) at tls.c:358 + frame #10: 0x000000000024c230 got-read-object`_init_tls at tls.c:468:8 + frame #11: 0x000000000022e0e4 got-read-object`_start(ap=, cleanup=) at crt1_c.c:65:3 + +and in jemalloc.c: + + /* + * Try to use the contents of the "/etc/malloc.conf" symbolic + * link's name. + */ +#ifndef JEMALLOC_READLINKAT + linklen = readlink(linkname, buf, PATH_MAX); +#else + linklen = readlinkat(AT_FDCWD, linkname, buf, PATH_MAX); +#endif + if (linklen == -1) { + /* No configuration specified. */ + linklen = 0; + /* Restore errno. */ + set_errno(saved_errno); + } +#endif + +They try calling readlink and if it gives an error they fix +it and move on, but obviously that doesn't work if the readlink +crashes the program +So I'm trying to temporarily change jemalloc to "fix" this, +but looking in /contrib/jemalloc there doesn't seem to be any way to make it? + +In got, they try opening progressively higher-up directories, to see if they +are repositories. However, we can't really do that in Capability mode. probably +will need to find it before entering capability mode, then just try once when +actually inside. +-> idea: make is_git_dir just take in a fd and a path, instead of a whole repo + (it doesn't seem like it actually needs it). or maybe make a fake repo with + just what is needed. Then we can go progressively higher up, looking for the + repo, before we enter capability mode. + +Remember to add the cap_getmode() in jemalloc + +TODO: +Change to dynamic linking +Fix #include order - many files +many functions - change param order +got_gotconfig_read - rights? ask +got_lockfile_lock - rights? +got_privsep_exec_child - ask about closefrom +got_repo_get_path_git_dir_fd - make name not obnoxiously long + +For other commands, need a "get repo path from worktree directory" function + -> because got_worktree_open now needs to take in the repo's fd, since we + call it in Capability mode + +CHANGES: +many paths become relative +worktree_path gets converted to absolute path before entering cap mode +find root repository directory before entering cap mode + -> got_repo_open now expects path to be the git directory of the repo +add rights restrictions whenever openat gets called +got_privsep_wait_for_child - use kqueue and pds instead of wait4 +got_privsep_exec_child - use fexecve instead of execl, programs statically linked +got_lockfile_unlock - unlink now uses new fd field of struct + +add fd parameter, change open() style to openat() style: +got_worktree_init +got_worktree_open +got_repo_init +got_repo_open +got_path_dir_is_empty +got_fileindex_entry_update +got_gotconfig_read +got_lockfile_lock +got_packidx_open +parse_ref_file +is_git_repo +open_ref +parse_gitconfig_file - now uses pdfork, for got_privsep_wait_for_child +other small helpers... + +new functions: +got_path_mkdirat +got_opentemp_opendir +got_repo_find_git_path +got_repo_get_path_fd +got_repo_get_path_git_dir_fd + +add fd field to structs: +got_lockfile +got_worktree +got_repository + diff --git a/got/got.c b/got/got.c index 52540c3a..82e4949b 100644 --- a/got/got.c +++ b/got/got.c @@ -58,6 +58,9 @@ #include "got_opentemp.h" #include "got_gotconfig.h" +#include +#include + #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif @@ -341,6 +344,7 @@ cmd_init(int argc, char *argv[]) const struct got_error *error = NULL; char *repo_path = NULL; int ch; + int repo_fd; while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { @@ -371,11 +375,16 @@ cmd_init(int argc, char *argv[]) !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; + repo_fd = open(repo_path, O_CREAT | O_DIRECTORY); + error = apply_unveil(repo_path, 0, NULL); if (error) goto done; - error = got_repo_init(repo_path); + if (caph_enter() < 0) + err(1, "cap_enter"); + + error = got_repo_init(repo_path, repo_fd); done: free(repo_path); return error; @@ -754,7 +763,8 @@ cmd_import(int argc, char *argv[]) error = get_gitconfig_path(&gitconfig_path); if (error) goto done; - error = got_repo_open(&repo, repo_path, gitconfig_path); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, gitconfig_path); if (error) goto done; @@ -775,7 +785,8 @@ cmd_import(int argc, char *argv[]) goto done; } - error = got_ref_open(&branch_ref, repo, refname, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&branch_ref, -1, refname, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; @@ -854,7 +865,8 @@ cmd_import(int argc, char *argv[]) goto done; } - error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, GOT_REF_HEAD, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) { if (logmsg_path) @@ -1169,7 +1181,7 @@ create_gotconfig(const char *proto, const char *host, const char *port, ssize_t n; /* Create got.conf(5). */ - gotconfig_path = got_repo_get_path_gotconfig(repo); + gotconfig_path = got_repo_get_path_gotconfig(); if (gotconfig_path == NULL) { err = got_error_from_errno("got_repo_get_path_gotconfig"); goto done; @@ -1490,10 +1502,12 @@ cmd_clone(int argc, char *argv[]) goto done; if (!list_refs_only) { - error = got_repo_init(repo_path); + int repo_fd = open(repo_path, O_RDWR | O_CREAT); + error = got_repo_init(repo_path, repo_fd); if (error) goto done; - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error) goto done; } @@ -1582,7 +1596,8 @@ cmd_clone(int argc, char *argv[]) if (strcmp(refname, GOT_REF_HEAD) != 0) continue; - error = got_ref_open(&target_ref, repo, target, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&target_ref, -1, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; @@ -1615,7 +1630,8 @@ cmd_clone(int argc, char *argv[]) free(remote_refname); goto done; } - error = got_ref_open(&target_ref, repo, remote_target, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&target_ref, -1, remote_target, 0); if (error) { free(remote_refname); free(remote_target); @@ -1643,7 +1659,8 @@ cmd_clone(int argc, char *argv[]) const char *target = pe->path; struct got_reference *target_ref; - error = got_ref_open(&target_ref, repo, target, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&target_ref, -1, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; @@ -1768,7 +1785,8 @@ update_symref(const char *refname, struct got_reference *target_ref, struct got_reference *symref; int symref_is_locked = 0; - err = got_ref_open(&symref, repo, refname, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&symref, -1, refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) return err; @@ -1925,7 +1943,8 @@ delete_missing_refs(struct got_pathlist_head *their_refs, if (local_refname) { struct got_reference *ref; - err = got_ref_open(&ref, repo, local_refname, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, local_refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) break; @@ -1968,7 +1987,8 @@ update_wanted_ref(const char *refname, struct got_object_id *id, remote_repo_name, refname) == -1) return got_error_from_errno("asprintf"); - err = got_ref_open(&ref, repo, remote_refname, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, remote_refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; @@ -2090,7 +2110,8 @@ cmd_fetch(int argc, char *argv[]) } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -2111,7 +2132,8 @@ cmd_fetch(int argc, char *argv[]) } } - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error) goto done; @@ -2260,7 +2282,8 @@ cmd_fetch(int argc, char *argv[]) if (remote->mirror_references || strncmp("refs/tags/", refname, 10) == 0) { - error = got_ref_open(&ref, repo, refname, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&ref, -1, refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; @@ -2285,7 +2308,8 @@ cmd_fetch(int argc, char *argv[]) goto done; } - error = got_ref_open(&ref, repo, remote_refname, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&ref, -1, remote_refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; @@ -2305,7 +2329,8 @@ cmd_fetch(int argc, char *argv[]) } /* Also create a local branch if none exists yet. */ - error = got_ref_open(&ref, repo, refname, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&ref, -1, refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; @@ -2354,7 +2379,8 @@ cmd_fetch(int argc, char *argv[]) goto done; } - error = got_ref_open(&target_ref, repo, remote_target, + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&target_ref, -1, remote_target, 0); if (error) { free(remote_refname); @@ -2609,6 +2635,7 @@ cmd_checkout(int argc, char *argv[]) int ch, same_path_prefix, allow_nonempty = 0; struct got_pathlist_head paths; struct got_checkout_progress_arg cpa; + cap_rights_t rights; TAILQ_INIT(&paths); @@ -2694,37 +2721,72 @@ cmd_checkout(int argc, char *argv[]) got_path_strip_trailing_slashes(repo_path); got_path_strip_trailing_slashes(worktree_path); - error = got_repo_open(&repo, repo_path, NULL); - if (error != NULL) - goto done; - /* Pre-create work tree path for unveil(2) */ error = got_path_mkdir(worktree_path); + int worktree_fd = open(worktree_path, O_DIRECTORY); if (error) { if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; if (!allow_nonempty && - !got_path_dir_is_empty(worktree_path)) { + !got_path_dir_is_empty(worktree_fd)) { error = got_error_path(worktree_path, GOT_ERR_DIR_NOT_EMPTY); goto done; } } - error = apply_unveil(got_repo_get_path(repo), 0, worktree_path); + /* Make worktree path absolute */ + char *real_wt_path = realpath(worktree_path, NULL); + if (real_wt_path == NULL) { + error = got_error_from_errno("realpath"); + goto done; + } + free(worktree_path); + worktree_path = real_wt_path; + + cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET, + CAP_SEEK, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_MKDIRAT, CAP_UNLINKAT, CAP_FLOCK, + CAP_FSYNC, CAP_FCHMOD); + if (caph_rights_limit(worktree_fd, &rights) < 0) + err(1, "caph_rights_limit"); + + error = got_repo_find_git_path(&repo_path); if (error) goto done; - error = got_ref_open(&head_ref, repo, branch_name, 0); + int repo_fd = open(repo_path, O_DIRECTORY); + cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET, CAP_MKDIRAT, + CAP_SEEK, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_UNLINKAT, CAP_FLOCK, CAP_FCHMOD, CAP_MMAP_R); + if (caph_rights_limit(repo_fd, &rights) < 0) + err(1, "caph_rights_limit"); + + error = apply_unveil(repo_path, 0, worktree_path); + if (error) + goto done; + + error = got_opentemp_opendir(); + if (error != NULL) + goto done; + + caph_cache_catpages(); + + if (caph_enter() < 0) + err(1, "caph_enter"); + + error = got_repo_open(&repo, repo_fd, repo_path, NULL); + if (error != NULL) + goto done; + + error = got_ref_open(&head_ref, got_repo_get_path_git_dir_fd(repo), branch_name, 0); if (error != NULL) goto done; - error = got_worktree_init(worktree_path, head_ref, path_prefix, repo); + error = got_worktree_init(worktree_fd, worktree_path, head_ref, path_prefix, repo); if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; - error = got_worktree_open(&worktree, worktree_path); + error = got_worktree_open(&worktree, worktree_fd, worktree_path, repo_fd); if (error != NULL) goto done; @@ -2947,7 +3009,8 @@ wrap_not_worktree_error(const struct got_error *orig_err, struct got_repository *repo; static char msg[512]; - err = got_repo_open(&repo, path, NULL); + printf("REPO_OPEN - BROKEN\n"); + err = got_repo_open(&repo, -1, path, NULL); if (err) return orig_err; @@ -3008,7 +3071,8 @@ cmd_update(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, worktree_path); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, worktree_path, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "update", @@ -3020,7 +3084,8 @@ cmd_update(int argc, char *argv[]) if (error) goto done; - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -3034,7 +3099,8 @@ cmd_update(int argc, char *argv[]) if (error) goto done; - error = got_ref_open(&head_ref, repo, branch_name ? branch_name : + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, branch_name ? branch_name : got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; @@ -3684,7 +3750,8 @@ resolve_commit_arg(struct got_object_id **id, const char *commit_arg, *id = NULL; - err = got_ref_open(&ref, repo, commit_arg, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, commit_arg, 0); if (err == NULL) { int obj_type; err = got_ref_resolve(id, repo, ref); @@ -3812,7 +3879,8 @@ cmd_log(int argc, char *argv[]) } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; error = NULL; @@ -3849,7 +3917,8 @@ cmd_log(int argc, char *argv[]) goto done; } - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error != NULL) goto done; @@ -3861,7 +3930,8 @@ cmd_log(int argc, char *argv[]) if (start_commit == NULL) { struct got_reference *head_ref; struct got_commit_object *commit = NULL; - error = got_ref_open(&head_ref, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) @@ -4193,7 +4263,8 @@ cmd_diff(int argc, char *argv[]) if (repo_path) errx(1, "-r option can't be used when diffing a work tree"); - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "diff", @@ -4224,7 +4295,8 @@ cmd_diff(int argc, char *argv[]) id_str1 = argv[0]; id_str2 = argv[1]; if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) { @@ -4245,7 +4317,8 @@ cmd_diff(int argc, char *argv[]) } else usage_diff(); - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); free(repo_path); if (error != NULL) goto done; @@ -4523,7 +4596,8 @@ cmd_blame(int argc, char *argv[]) goto done; } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -4545,7 +4619,8 @@ cmd_blame(int argc, char *argv[]) } } - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error != NULL) goto done; @@ -4574,7 +4649,8 @@ cmd_blame(int argc, char *argv[]) if (commit_id_str == NULL) { struct got_reference *head_ref; - error = got_ref_open(&head_ref, repo, worktree ? + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; @@ -4849,7 +4925,8 @@ cmd_tree(int argc, char *argv[]) goto done; } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -4870,7 +4947,8 @@ cmd_tree(int argc, char *argv[]) } } - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error != NULL) goto done; @@ -4907,7 +4985,8 @@ cmd_tree(int argc, char *argv[]) refname = got_worktree_get_head_ref_name(worktree); else refname = GOT_REF_HEAD; - error = got_ref_open(&head_ref, repo, refname, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, refname, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); @@ -5026,14 +5105,16 @@ cmd_status(int argc, char *argv[]) goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "status", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -5098,7 +5179,8 @@ delete_ref(struct got_repository *repo, const char *refname) const struct got_error *err = NULL; struct got_reference *ref; - err = got_ref_open(&ref, repo, refname, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, refname, 0); if (err) return err; @@ -5129,7 +5211,8 @@ add_ref(struct got_repository *repo, const char *refname, const char *target) if (err->code != GOT_ERR_BAD_OBJ_ID_STR) return err; - err = got_ref_open(&target_ref, repo, target, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&target_ref, -1, target, 0); if (err) return err; err = got_ref_resolve(&id, repo, target_ref); @@ -5165,7 +5248,8 @@ add_symref(struct got_repository *repo, const char *refname, const char *target) if (refname[0] == '-') return got_error_path(refname, GOT_ERR_REF_NAME_MINUS); - err = got_ref_open(&target_ref, repo, target, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&target_ref, -1, target, 0); if (err) return err; @@ -5277,7 +5361,8 @@ cmd_ref(int argc, char *argv[]) } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -5298,7 +5383,8 @@ cmd_ref(int argc, char *argv[]) } } - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error != NULL) goto done; @@ -5419,7 +5505,8 @@ list_branches(struct got_repository *repo, struct got_worktree *worktree) return err; if (rebase_in_progress || histedit_in_progress) { - err = got_ref_open(&temp_ref, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&temp_ref, -1, got_worktree_get_head_ref_name(worktree), 0); if (err) return err; @@ -5451,7 +5538,8 @@ delete_branch(struct got_repository *repo, struct got_worktree *worktree, if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) return got_error_from_errno("asprintf"); - err = got_ref_open(&ref, repo, refname, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, refname, 0); if (err) goto done; @@ -5492,7 +5580,8 @@ add_branch(struct got_repository *repo, const char *branch_name, goto done; } - err = got_ref_open(&ref, repo, refname, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, refname, 0); if (err == NULL) { err = got_error(GOT_ERR_BRANCH_EXISTS); goto done; @@ -5592,7 +5681,8 @@ cmd_branch(int argc, char *argv[]) } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -5613,7 +5703,8 @@ cmd_branch(int argc, char *argv[]) } } - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error != NULL) goto done; @@ -5656,7 +5747,8 @@ cmd_branch(int argc, char *argv[]) error = got_error_from_errno("asprintf"); goto done; } - error = got_ref_open(&ref, repo, branch_refname, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&ref, -1, branch_refname, 0); free(branch_refname); if (error) goto done; @@ -5985,7 +6077,8 @@ add_tag(struct got_repository *repo, struct got_worktree *worktree, goto done; } - err = got_ref_open(&ref, repo, refname, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, refname, 0); if (err == NULL) { err = got_error(GOT_ERR_TAG_EXISTS); goto done; @@ -6119,7 +6212,8 @@ cmd_tag(int argc, char *argv[]) } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -6141,7 +6235,8 @@ cmd_tag(int argc, char *argv[]) } if (do_list) { - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, NULL); @@ -6152,7 +6247,8 @@ cmd_tag(int argc, char *argv[]) error = get_gitconfig_path(&gitconfig_path); if (error) goto done; - error = got_repo_open(&repo, repo_path, gitconfig_path); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, gitconfig_path); if (error != NULL) goto done; @@ -6165,7 +6261,8 @@ cmd_tag(int argc, char *argv[]) if (commit_id_arg == NULL) { struct got_reference *head_ref; struct got_object_id *commit_id; - error = got_ref_open(&head_ref, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error) @@ -6256,14 +6353,16 @@ cmd_add(int argc, char *argv[]) goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "add", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -6411,14 +6510,16 @@ cmd_remove(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "remove", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error) goto done; @@ -6660,14 +6761,16 @@ cmd_revert(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "revert", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -6865,7 +6968,8 @@ cmd_commit(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "commit", cwd); @@ -6888,7 +6992,8 @@ cmd_commit(int argc, char *argv[]) error = get_gitconfig_path(&gitconfig_path); if (error) goto done; - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), gitconfig_path); if (error != NULL) goto done; @@ -7004,7 +7109,8 @@ cmd_cherrypick(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "cherrypick", @@ -7012,7 +7118,8 @@ cmd_cherrypick(int argc, char *argv[]) goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -7028,7 +7135,8 @@ cmd_cherrypick(int argc, char *argv[]) struct got_reference *ref; if (error->code != GOT_ERR_BAD_OBJ_ID_STR) goto done; - error = got_ref_open(&ref, repo, argv[0], 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&ref, -1, argv[0], 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, ref); @@ -7040,7 +7148,8 @@ cmd_cherrypick(int argc, char *argv[]) if (error) goto done; - error = got_ref_open(&head_ref, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; @@ -7127,14 +7236,16 @@ cmd_backout(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "backout", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -7150,7 +7261,8 @@ cmd_backout(int argc, char *argv[]) struct got_reference *ref; if (error->code != GOT_ERR_BAD_OBJ_ID_STR) goto done; - error = got_ref_open(&ref, repo, argv[0], 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&ref, -1, argv[0], 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, ref); @@ -7162,7 +7274,8 @@ cmd_backout(int argc, char *argv[]) if (error) goto done; - error = got_ref_open(&head_ref, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&head_ref, -1, got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; @@ -7535,14 +7648,16 @@ cmd_rebase(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "rebase", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -7610,7 +7725,8 @@ cmd_rebase(int argc, char *argv[]) goto done; } } else { - error = got_ref_open(&branch, repo, argv[0], 0); + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&branch, -1, argv[0], 0); if (error != NULL) goto done; } @@ -8265,7 +8381,8 @@ histedit_edit_script(struct got_histedit_list *histedit_cmds, FILE *f = NULL; char *path = NULL; - err = got_opentemp_named(&path, &f, "got-histedit"); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &path, &f, "got-histedit"); if (err) return err; @@ -8668,14 +8785,16 @@ cmd_histedit(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "histedit", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -8771,7 +8890,8 @@ cmd_histedit(int argc, char *argv[]) goto done; } - error = got_ref_open(&branch, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + error = got_ref_open(&branch, -1, got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; @@ -9050,7 +9170,8 @@ cmd_integrate(int argc, char *argv[]) goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "integrate", @@ -9062,7 +9183,8 @@ cmd_integrate(int argc, char *argv[]) if (error) goto done; - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -9235,14 +9357,16 @@ cmd_stage(int argc, char *argv[]) goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "stage", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -9348,14 +9472,16 @@ cmd_unstage(int argc, char *argv[]) goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "unstage", cwd); goto done; } - error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, got_worktree_get_repo_path(worktree), NULL); if (error != NULL) goto done; @@ -9602,7 +9728,8 @@ cmd_cat(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) { @@ -9622,7 +9749,8 @@ cmd_cat(int argc, char *argv[]) return got_error_from_errno("getcwd"); } - error = got_repo_open(&repo, repo_path, NULL); + printf("REPO_OPEN - BROKEN\n"); + error = got_repo_open(&repo, -1, repo_path, NULL); free(repo_path); if (error != NULL) goto done; @@ -9812,7 +9940,8 @@ cmd_info(int argc, char *argv[]) goto done; } - error = got_worktree_open(&worktree, cwd); + printf("WORKTREE_OPEN - BROKEN\n"); + error = got_worktree_open(&worktree, -1, cwd, -1); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "status", cwd); diff --git a/include/got_opentemp.h b/include/got_opentemp.h index 82d4fbdc..2f64c9c8 100644 --- a/include/got_opentemp.h +++ b/include/got_opentemp.h @@ -23,6 +23,12 @@ #define GOT_STRINGVAL_TMP(x) GOT_STRINGIFY_TMP(x) #define GOT_TMPDIR_STR GOT_STRINGVAL_TMP(GOT_TMPDIR) +/* + * Open the temporary file directory, for later use in + * Capability mode. + */ +const struct got_error *got_opentemp_opendir(void); + /* Open a file descriptor to a new temporary file for writing. * The file is not visible in the filesystem. */ int got_opentempfd(void); @@ -33,7 +39,7 @@ FILE *got_opentemp(void); /* Open a new temporary file for writing. * The file is visible in the filesystem. */ -const struct got_error *got_opentemp_named(char **, FILE **, const char *); +const struct got_error *got_opentemp_named(int, char **, FILE **, const char *); /* Like got_opentemp_named() but returns a file descriptor instead of a FILE. */ const struct got_error *got_opentemp_named_fd(char **, int *, const char *); diff --git a/include/got_path.h b/include/got_path.h index 0219d3d3..d925ba6b 100644 --- a/include/got_path.h +++ b/include/got_path.h @@ -98,8 +98,14 @@ void got_pathlist_free(struct got_pathlist_head *); /* Attempt to create a directory at a given path. */ const struct got_error *got_path_mkdir(const char *); +/* + * Attempt to create a directory at a given path relative to + * a file descriptor. + */ +const struct got_error *got_path_mkdirat(int, const char *); + /* Determine whether a directory has no files or directories in it. */ -int got_path_dir_is_empty(const char *); +int got_path_dir_is_empty(int); /* * dirname(3) with error handling, dynamically allocated result, and @@ -131,4 +137,4 @@ void got_path_strip_trailing_slashes(char *); const struct got_error *got_path_find_prog(char **, const char *); /* Create a new file at a specified path, with optional content. */ -const struct got_error *got_path_create_file(const char *, const char *); +const struct got_error *got_path_create_file(int, const char *, const char *); diff --git a/include/got_reference.h b/include/got_reference.h index 5f2594f5..30888296 100644 --- a/include/got_reference.h +++ b/include/got_reference.h @@ -34,7 +34,7 @@ struct got_object_id; * must be unlocked with got_ref_unlock() before got_ref_close() is called. */ const struct got_error *got_ref_open(struct got_reference **, - struct got_repository *, const char *, int); + int, const char *, int); /* * Allocate a new reference for a given object ID. diff --git a/include/got_repository.h b/include/got_repository.h index 20f873a5..b87ac732 100644 --- a/include/got_repository.h +++ b/include/got_repository.h @@ -18,20 +18,32 @@ struct got_repository; struct got_pathlist_head; struct got_tag_object; +/* + * Given a path inside a repository, modify it to be + * the path to the root of the repository. + */ +const struct got_error *got_repo_find_git_path(char **); + /* Open and close repositories. */ -const struct got_error *got_repo_open(struct got_repository**, const char *, +const struct got_error *got_repo_open(struct got_repository**, int, const char *, const char *); const struct got_error *got_repo_close(struct got_repository*); /* Obtain the on-disk path to the repository. */ const char *got_repo_get_path(struct got_repository *); +/* Obtain the file descriptor of the on-disk path. */ +int got_repo_get_path_fd(struct got_repository *); + /* * Obtain the path to a non-bare repository's .git directory. * For bare repositories, this returns the same result as got_repo_get_path(). */ const char *got_repo_get_path_git_dir(struct got_repository *); +/* Obtain the file descriptor of the repository's .git directory. */ +int got_repo_get_path_git_dir_fd(struct got_repository *); + /* Obtain the commit author name if parsed from gitconfig, else NULL. */ const char *got_repo_get_gitconfig_author_name(struct got_repository *); @@ -83,12 +95,12 @@ const struct got_gotconfig *got_repo_get_gotconfig(struct got_repository *); * Obtain paths to various directories within a repository. * The caller must dispose of a path with free(3). */ -char *got_repo_get_path_objects(struct got_repository *); -char *got_repo_get_path_objects_pack(struct got_repository *); -char *got_repo_get_path_refs(struct got_repository *); -char *got_repo_get_path_packed_refs(struct got_repository *); +char *got_repo_get_path_objects(void); +char *got_repo_get_path_objects_pack(void); +char *got_repo_get_path_refs(void); +char *got_repo_get_path_packed_refs(void); char *got_repo_get_path_gitconfig(struct got_repository *); -char *got_repo_get_path_gotconfig(struct got_repository *); +char *got_repo_get_path_gotconfig(void); struct got_reference; @@ -108,7 +120,7 @@ const struct got_error *got_repo_map_path(char **, struct got_repository *, const char *, int); /* Create a new repository in an empty directory at a specified path. */ -const struct got_error *got_repo_init(const char *); +const struct got_error *got_repo_init(const char *, int); /* Attempt to find a unique object ID for a given ID string prefix. */ const struct got_error *got_repo_match_object_id_prefix(struct got_object_id **, diff --git a/include/got_worktree.h b/include/got_worktree.h index 24fddd52..b30f994b 100644 --- a/include/got_worktree.h +++ b/include/got_worktree.h @@ -42,19 +42,18 @@ struct got_fileindex; /* * Attempt to initialize a new work tree on disk. * The first argument is the path to a directory where the work tree - * will be created. The path itself must not yet exist, but the dirname(3) - * of the path must already exist. + * will be created. The dirname(3) of the path must already exist. * The reference provided will be used to determine the new worktree's * base commit. The third argument speficies the work tree's path prefix. */ -const struct got_error *got_worktree_init(const char *, struct got_reference *, +const struct got_error *got_worktree_init(int, const char *, struct got_reference *, const char *, struct got_repository *); /* * Attempt to open a worktree at or above the specified path. * The caller must dispose of it with got_worktree_close(). */ -const struct got_error *got_worktree_open(struct got_worktree **, const char *); +const struct got_error *got_worktree_open(struct got_worktree **, int, const char *, int); /* Dispose of an open work tree. */ const struct got_error *got_worktree_close(struct got_worktree *); diff --git a/lib/diff3.c b/lib/diff3.c index 163577c9..36ed9b2f 100644 --- a/lib/diff3.c +++ b/lib/diff3.c @@ -221,7 +221,8 @@ diffreg(BUF **d, const char *path1, const char *path2) goto done; } - err = got_opentemp_named(&outpath, &outfile, + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &outpath, &outfile, GOT_TMPDIR_STR "/got-diffreg"); if (err) goto done; diff --git a/lib/fileindex.c b/lib/fileindex.c index b46dbb29..e5f30742 100644 --- a/lib/fileindex.c +++ b/lib/fileindex.c @@ -88,23 +88,22 @@ got_fileindex_perms_to_st(struct got_fileindex_entry *ie) const struct got_error * got_fileindex_entry_update(struct got_fileindex_entry *ie, - const char *ondisk_path, uint8_t *blob_sha1, uint8_t *commit_sha1, + int wt_fd, const char *path, uint8_t *blob_sha1, uint8_t *commit_sha1, int update_timestamps) { struct stat sb; - if (lstat(ondisk_path, &sb) != 0) { + if (fstatat(wt_fd, path, &sb, 0) != 0) { if (!((ie->flags & GOT_FILEIDX_F_NO_FILE_ON_DISK) && errno == ENOENT)) - return got_error_from_errno2("lstat", ondisk_path); + return got_error_from_errno2("fstatat", path); sb.st_mode = GOT_DEFAULT_FILE_MODE; } else { if (sb.st_mode & S_IFDIR) - return got_error_set_errno(EISDIR, ondisk_path); + return got_error_set_errno(EISDIR, path); ie->flags &= ~GOT_FILEIDX_F_NO_FILE_ON_DISK; } - if ((ie->flags & GOT_FILEIDX_F_NO_FILE_ON_DISK) == 0) { if (update_timestamps) { ie->ctime_sec = sb.st_ctim.tv_sec; diff --git a/lib/got_lib_fileindex.h b/lib/got_lib_fileindex.h index f1005832..537374d7 100644 --- a/lib/got_lib_fileindex.h +++ b/lib/got_lib_fileindex.h @@ -108,7 +108,7 @@ uint16_t got_fileindex_perms_from_st(struct stat *); mode_t got_fileindex_perms_to_st(struct got_fileindex_entry *); const struct got_error *got_fileindex_entry_update(struct got_fileindex_entry *, - const char *, uint8_t *, uint8_t *, int); + int, const char *, uint8_t *, uint8_t *, int); const struct got_error *got_fileindex_entry_alloc(struct got_fileindex_entry **, const char *); void got_fileindex_entry_free(struct got_fileindex_entry *); diff --git a/lib/got_lib_gotconfig.h b/lib/got_lib_gotconfig.h index 5e02aa1e..01d9a027 100644 --- a/lib/got_lib_gotconfig.h +++ b/lib/got_lib_gotconfig.h @@ -23,5 +23,5 @@ struct got_gotconfig { }; const struct got_error *got_gotconfig_read(struct got_gotconfig **, - const char *); + const char *, int); void got_gotconfig_free(struct got_gotconfig *); diff --git a/lib/got_lib_lockfile.h b/lib/got_lib_lockfile.h index 379232fe..5036ca2b 100644 --- a/lib/got_lib_lockfile.h +++ b/lib/got_lib_lockfile.h @@ -24,8 +24,9 @@ struct got_lockfile { char *path; char *locked_path; + int root_fd; int fd; }; -const struct got_error *got_lockfile_lock(struct got_lockfile **, const char *); +const struct got_error *got_lockfile_lock(struct got_lockfile **, int, const char *); const struct got_error *got_lockfile_unlock(struct got_lockfile *); diff --git a/lib/got_lib_object.h b/lib/got_lib_object.h index 989af7a5..30d127e8 100644 --- a/lib/got_lib_object.h +++ b/lib/got_lib_object.h @@ -87,8 +87,7 @@ struct got_tag_object { struct got_object_id *got_object_get_id(struct got_object *); const struct got_error *got_object_get_id_str(char **, struct got_object *); -const struct got_error *got_object_get_path(char **, struct got_object_id *, - struct got_repository *); +const struct got_error *got_object_get_path(char **, struct got_object_id *); const struct got_error *got_object_open(struct got_object **, struct got_repository *, struct got_object_id *); const struct got_error *got_object_open_by_id_str(struct got_object **, diff --git a/lib/got_lib_pack.h b/lib/got_lib_pack.h index c56e16c4..39aa4333 100644 --- a/lib/got_lib_pack.h +++ b/lib/got_lib_pack.h @@ -168,7 +168,7 @@ struct got_packfile_obj_data { const struct got_error *got_packidx_init_hdr(struct got_packidx *, int); const struct got_error *got_packidx_open(struct got_packidx **, - const char *, int); + int, const char *, int); const struct got_error *got_packidx_close(struct got_packidx *); int got_packidx_get_object_idx(struct got_packidx *, struct got_object_id *); const struct got_error *got_packidx_match_id_str_prefix( diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h index 6c638e9d..47a58f25 100644 --- a/lib/got_lib_privsep.h +++ b/lib/got_lib_privsep.h @@ -396,7 +396,7 @@ struct got_packidx; struct got_pathlist_head; const struct got_error *got_send_ack(pid_t); -const struct got_error *got_privsep_wait_for_child(pid_t); +const struct got_error *got_privsep_wait_for_child(int); const struct got_error *got_privsep_flush_imsg(struct imsgbuf *); const struct got_error *got_privsep_send_stop(int); const struct got_error *got_privsep_recv_imsg(struct imsg *, struct imsgbuf *, diff --git a/lib/got_lib_repository.h b/lib/got_lib_repository.h index 87f25580..f091e0bd 100644 --- a/lib/got_lib_repository.h +++ b/lib/got_lib_repository.h @@ -34,6 +34,8 @@ struct got_repository { char *path; char *path_git_dir; + int path_fd; + int path_git_dir_fd; /* The pack index cache speeds up search for packed objects. */ struct got_packidx *packidx_cache[GOT_PACKIDX_CACHE_SIZE]; diff --git a/lib/got_lib_worktree.h b/lib/got_lib_worktree.h index 067bac22..2a1f9582 100644 --- a/lib/got_lib_worktree.h +++ b/lib/got_lib_worktree.h @@ -17,6 +17,8 @@ struct got_worktree { char *root_path; char *repo_path; + int root_fd; + int repo_fd; char *path_prefix; struct got_object_id *base_commit_id; char *head_ref_name; diff --git a/lib/gotconfig.c b/lib/gotconfig.c index d88814a1..269085b9 100644 --- a/lib/gotconfig.c +++ b/lib/gotconfig.c @@ -40,25 +40,32 @@ #include "got_lib_privsep.h" #include "got_lib_gotconfig.h" +#include +#include + const struct got_error * -got_gotconfig_read(struct got_gotconfig **conf, const char *gotconfig_path) +got_gotconfig_read(struct got_gotconfig **conf, const char *gotconfig_path, int git_fd) { const struct got_error *err = NULL, *child_err = NULL; int fd = -1; int imsg_fds[2] = { -1, -1 }; pid_t pid; struct imsgbuf *ibuf; + cap_rights_t rights; *conf = calloc(1, sizeof(**conf)); if (*conf == NULL) return got_error_from_errno("calloc"); - fd = open(gotconfig_path, O_RDONLY); + fd = openat(git_fd, gotconfig_path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) return NULL; return got_error_from_errno2("open", gotconfig_path); } + cap_rights_init(&rights); //NOTE: for some reason this still works? + if (caph_rights_limit(fd, &rights) < 0) + return got_error_from_errno("caph_rights_limit"); ibuf = calloc(1, sizeof(*ibuf)); if (ibuf == NULL) { diff --git a/lib/lockfile.c b/lib/lockfile.c index 2e718693..20783815 100644 --- a/lib/lockfile.c +++ b/lib/lockfile.c @@ -32,17 +32,23 @@ #include "got_lib_lockfile.h" +#include +#include + const struct got_error * -got_lockfile_lock(struct got_lockfile **lf, const char *path) +got_lockfile_lock(struct got_lockfile **lf, int root_fd, const char *path) { const struct got_error *err = NULL; int attempts = 5; + cap_rights_t rights; *lf = calloc(1, sizeof(**lf)); if (*lf == NULL) return got_error_from_errno("calloc"); (*lf)->fd = -1; + (*lf)->root_fd = root_fd; + (*lf)->locked_path = strdup(path); if ((*lf)->locked_path == NULL) { err = got_error_from_errno("strdup"); @@ -55,7 +61,7 @@ got_lockfile_lock(struct got_lockfile **lf, const char *path) } do { - (*lf)->fd = open((*lf)->path, + (*lf)->fd = openat(root_fd, (*lf)->path, O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK, GOT_DEFAULT_FILE_MODE); if ((*lf)->fd != -1) @@ -69,6 +75,10 @@ got_lockfile_lock(struct got_lockfile **lf, const char *path) if ((*lf)->fd == -1) err = got_error(GOT_ERR_LOCKFILE_TIMEOUT); + + cap_rights_init(&rights); //NOTE: also doesn't seem to affect anything? + if (caph_rights_limit((*lf)->fd, &rights) < 0) + err = got_error_from_errno("caph_rights_limit"); done: if (err) { got_lockfile_unlock(*lf); @@ -82,8 +92,8 @@ got_lockfile_unlock(struct got_lockfile *lf) { const struct got_error *err = NULL; - if (lf->path && lf->fd != -1 && unlink(lf->path) != 0) - err = got_error_from_errno("unlink"); + if (lf->path && lf->fd != -1 && unlinkat(lf->root_fd, lf->path, 0) != 0) + err = got_error_from_errno("unlinkat"); if (lf->fd != -1 && close(lf->fd) != 0 && err == NULL) err = got_error_from_errno("close"); free(lf->path); diff --git a/lib/object.c b/lib/object.c index 852c8c8b..39935510 100644 --- a/lib/object.c +++ b/lib/object.c @@ -56,6 +56,8 @@ #include "got_lib_pack.h" #include "got_lib_repository.h" +#include + #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif @@ -100,8 +102,7 @@ got_object_get_type(int *type, struct got_repository *repo, } const struct got_error * -got_object_get_path(char **path, struct got_object_id *id, - struct got_repository *repo) +got_object_get_path(char **path, struct got_object_id *id) { const struct got_error *err = NULL; char *hex = NULL; @@ -109,7 +110,7 @@ got_object_get_path(char **path, struct got_object_id *id, *path = NULL; - path_objects = got_repo_get_path_objects(repo); + path_objects = got_repo_get_path_objects(); if (path_objects == NULL) return got_error_from_errno("got_repo_get_path_objects"); @@ -133,15 +134,19 @@ open_loose_object(int *fd, struct got_object_id *id, { const struct got_error *err = NULL; char *path; + cap_rights_t rights; - err = got_object_get_path(&path, id, repo); + err = got_object_get_path(&path, id); if (err) return err; - *fd = open(path, O_RDONLY | O_NOFOLLOW); + *fd = openat(got_repo_get_path_git_dir_fd(repo), path, O_RDONLY | O_NOFOLLOW); if (*fd == -1) { err = got_error_from_errno2("open", path); goto done; } + cap_rights_init(&rights, CAP_READ, CAP_FCNTL, CAP_SEEK, CAP_FSTAT); + if (caph_rights_limit(*fd, &rights) < 0) + err = got_error_from_errno("caph_rights_limit"); done: free(path); return err; @@ -401,11 +406,11 @@ got_object_open(struct got_object **obj, struct got_repository *repo, return got_repo_cache_object(repo, id, *obj); } - err = got_object_get_path(&path, id, repo); + err = got_object_get_path(&path, id); if (err) return err; - fd = open(path, O_RDONLY | O_NOFOLLOW); + fd = openat(got_repo_get_path_git_dir_fd(repo), path, O_RDONLY | O_NOFOLLOW); if (fd == -1) { if (errno == ENOENT) err = got_error_no_obj(id); diff --git a/lib/object_create.c b/lib/object_create.c index 6c4efe0b..5b5a3445 100644 --- a/lib/object_create.c +++ b/lib/object_create.c @@ -59,11 +59,12 @@ create_object_file(struct got_object_id *id, FILE *content, struct got_lockfile *lf = NULL; size_t tmplen = 0; - err = got_object_get_path(&objpath, id, repo); + err = got_object_get_path(&objpath, id); if (err) return err; - err = got_opentemp_named(&tmppath, &tmpfile, objpath); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &tmppath, &tmpfile, objpath); if (err) { char *parent_path; if (!(err->code == GOT_ERR_ERRNO && errno == ENOENT)) @@ -75,7 +76,8 @@ create_object_file(struct got_object_id *id, FILE *content, free(parent_path); if (err) goto done; - err = got_opentemp_named(&tmppath, &tmpfile, objpath); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &tmppath, &tmpfile, objpath); if (err) goto done; } @@ -84,7 +86,7 @@ create_object_file(struct got_object_id *id, FILE *content, if (err) goto done; - err = got_lockfile_lock(&lf, objpath); + err = got_lockfile_lock(&lf, got_repo_get_path_git_dir_fd(repo), objpath); if (err) goto done; diff --git a/lib/opentemp.c b/lib/opentemp.c index 73f48d7f..82c72c9e 100644 --- a/lib/opentemp.c +++ b/lib/opentemp.c @@ -25,19 +25,40 @@ #include "got_opentemp.h" #include "got_error.h" +#include +#include +#include + +static int tempdir_fd; + +const struct got_error * +got_opentemp_opendir(void) +{ + cap_rights_t rights; + + tempdir_fd = open(GOT_TMPDIR_STR, O_DIRECTORY); + if (tempdir_fd == -1) + return got_error_from_errno("open"); + cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_LOOKUP, CAP_CREATE, + CAP_FCNTL, CAP_UNLINKAT, CAP_FSTAT, CAP_SEEK); + if (caph_rights_limit(tempdir_fd, &rights) < 0) + return got_error_from_errno("caph_rights_limit"); + return NULL; +} + int got_opentempfd(void) { char name[PATH_MAX]; int fd; - if (strlcpy(name, GOT_TMPDIR_STR "/got.XXXXXXXX", sizeof(name)) + if (strlcpy(name, "got.XXXXXXXX", sizeof(name)) >= sizeof(name)) return -1; - fd = mkstemp(name); + fd = mkostempsat(tempdir_fd, name, 0, 0); if (fd != -1) - unlink(name); + unlinkat(tempdir_fd, name, 0); return fd; } @@ -61,7 +82,7 @@ got_opentemp(void) } const struct got_error * -got_opentemp_named(char **path, FILE **outfile, const char *basepath) +got_opentemp_named(int dir_fd, char **path, FILE **outfile, const char *basepath) { const struct got_error *err = NULL; int fd; @@ -73,9 +94,9 @@ got_opentemp_named(char **path, FILE **outfile, const char *basepath) return got_error_from_errno("asprintf"); } - fd = mkstemp(*path); + fd = mkostempsat(dir_fd, *path, 0, 0); if (fd == -1) { - err = got_error_from_errno2("mkstemp", *path); + err = got_error_from_errno2("mkostempsat", *path); free(*path); *path = NULL; return err; diff --git a/lib/pack.c b/lib/pack.c index 3ce002a8..57a45f9a 100644 --- a/lib/pack.c +++ b/lib/pack.c @@ -49,6 +49,9 @@ #include "got_lib_privsep.h" #include "got_lib_pack.h" +#include +#include + #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif @@ -330,11 +333,12 @@ done: } const struct got_error * -got_packidx_open(struct got_packidx **packidx, const char *path, int verify) +got_packidx_open(struct got_packidx **packidx, int packdir_fd, const char *path, int verify) { const struct got_error *err = NULL; struct got_packidx *p; struct stat sb; + cap_rights_t rights; *packidx = NULL; @@ -342,12 +346,17 @@ got_packidx_open(struct got_packidx **packidx, const char *path, int verify) if (p == NULL) return got_error_from_errno("calloc"); - p->fd = open(path, O_RDONLY | O_NOFOLLOW); + p->fd = openat(packdir_fd, path, O_RDONLY | O_NOFOLLOW); if (p->fd == -1) { - err = got_error_from_errno2("open", path); + err = got_error_from_errno2("openat", path); free(p); return err; } + cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R); + if (caph_rights_limit(p->fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + return err; + } if (fstat(p->fd, &sb) != 0) { err = got_error_from_errno2("fstat", path); diff --git a/lib/path.c b/lib/path.c index a670334c..bd05c4b9 100644 --- a/lib/path.c +++ b/lib/path.c @@ -35,6 +35,9 @@ #include "got_error.h" #include "got_path.h" +#include +#include + #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif @@ -313,6 +316,33 @@ done: return err; } +static const struct got_error * +make_parent_dirs_at(int fd, const char *abspath) +{ + const struct got_error *err = NULL; + char *parent; + + err = got_path_dirname(&parent, abspath); + if (err) + return err; + + if (mkdirat(fd, parent, GOT_DEFAULT_DIR_MODE) == -1) { + if (errno == ENOENT) { + err = make_parent_dirs_at(fd, parent); + if (err) + goto done; + if (mkdirat(fd, parent, GOT_DEFAULT_DIR_MODE) == -1) { + err = got_error_from_errno2("mkdir", parent); + goto done; + } + } else + err = got_error_from_errno2("mkdir", parent); + } +done: + free(parent); + return err; +} + const struct got_error * got_path_mkdir(const char *abspath) { @@ -333,14 +363,36 @@ done: return err; } +const struct got_error * +got_path_mkdirat(int fd, const char *path) +{ + const struct got_error *err = NULL; + + if (mkdirat(fd, path, GOT_DEFAULT_DIR_MODE) == -1) { + if (errno == ENOENT) { + err = make_parent_dirs_at(fd, path); + if (err) + goto done; + if (mkdirat(fd, path, GOT_DEFAULT_DIR_MODE) == -1) + err = got_error_from_errno2("mkdirat", path); + } else + err = got_error_from_errno2("mkdirat", path); + } + +done: + return err; +} + int -got_path_dir_is_empty(const char *dir) +got_path_dir_is_empty(int fd) { DIR *d; struct dirent *dent; + int fd_dup; int empty = 1; - d = opendir(dir); + fd_dup = dup(fd); + d = fdopendir(fd_dup); if (d == NULL) return 1; @@ -512,15 +564,22 @@ got_path_find_prog(char **filename, const char *prog) } const struct got_error * -got_path_create_file(const char *path, const char *content) +got_path_create_file(int dir_fd, const char *path, const char *content) { const struct got_error *err = NULL; int fd = -1; + cap_rights_t rights; - fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, + fd = openat(dir_fd, path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, GOT_DEFAULT_FILE_MODE); if (fd == -1) { - err = got_error_from_errno2("open", path); + err = got_error_from_errno2("openat", path); + goto done; + } + + cap_rights_init(&rights, CAP_READ, CAP_WRITE); + if (cap_rights_limit(fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); goto done; } diff --git a/lib/privsep.c b/lib/privsep.c index 1623faa8..70e90a4a 100644 --- a/lib/privsep.c +++ b/lib/privsep.c @@ -49,6 +49,13 @@ #include "got_lib_privsep.h" #include "got_lib_pack.h" +#include +#include +#include +#include +#include +#include + #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif @@ -101,18 +108,22 @@ read_imsg(struct imsgbuf *ibuf) return NULL; } +static int kq; + const struct got_error * -got_privsep_wait_for_child(pid_t pid) +got_privsep_wait_for_child(int pd) { int child_status; + struct kevent event; + + EV_SET(&event, pd, EVFILT_PROCDESC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL); - if (waitpid(pid, &child_status, 0) == -1) - return got_error_from_errno("waitpid"); + kevent(kq, &event, 1, &event, 1, NULL); - if (!WIFEXITED(child_status)) + if (!WIFEXITED(event.data)) return got_error(GOT_ERR_PRIVSEP_DIED); - if (WEXITSTATUS(child_status) != 0) + if (WEXITSTATUS(event.data) != 0) return got_error(GOT_ERR_PRIVSEP_EXIT); return NULL; @@ -2239,6 +2250,12 @@ got_privsep_recv_traversed_commits(struct got_commit_object **changed_commit, return err; } +static nvlist_t *helper_nv; +static int rtld_fd; +static int lib_fd; +static int usr_lib_fd; +static int openbsd_compat_fd; + const struct got_error * got_privsep_unveil_exec_helpers(void) { @@ -2255,19 +2272,46 @@ got_privsep_unveil_exec_helpers(void) GOT_PATH_PROG_INDEX_PACK, }; size_t i; + int fd; + cap_rights_t rights; + + helper_nv = nvlist_create(0); + cap_rights_init(&rights, CAP_FEXECVE); for (i = 0; i < nitems(helpers); i++) { - if (unveil(helpers[i], "x") == 0) - continue; - return got_error_from_errno2("unveil", helpers[i]); + fd = open(helpers[i], O_RDONLY); + if (caph_rights_limit(fd, &rights) < 0) + return got_error_from_errno("caph_rights_limit"); + nvlist_move_descriptor(helper_nv, helpers[i], fd); } + rtld_fd = open("/libexec/ld-elf.so.1", O_RDONLY); + if (rtld_fd == -1) + return got_error_from_errno("open"); + + lib_fd = open("/lib", O_DIRECTORY); + if (lib_fd == -1) + return got_error_from_errno("open"); + + usr_lib_fd = open("/usr/lib", O_DIRECTORY); + if (usr_lib_fd == -1) + return got_error_from_errno("open"); + + kq = kqueue(); + if (kq == -1) + return got_error_from_errno("kqueue"); + return NULL; } void got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path) { + const char **argv; + int fd = nvlist_get_descriptor(helper_nv, path); + char *fd_buf; + char *library_path_fds_buf; + if (close(imsg_fds[0]) != 0) { fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno)); _exit(1); @@ -2277,12 +2321,28 @@ got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path) fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno)); _exit(1); } + /* NOTE need to ask about this part if (closefrom(GOT_IMSG_FD_CHILD + 1) == -1) { fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno)); _exit(1); } - - if (execl(path, path, repo_path, (char *)NULL) == -1) { + */ + + argv = malloc(sizeof(char *) * 7); + argv[0] = path; + argv[1] = repo_path; + argv[2] = (char *) NULL; + /* + argv[0] = "/libexec/ld-elf.so.1"; + argv[1] = "-f"; + argv[2] = fd_buf; + argv[3] = "--"; + argv[4] = path; + argv[5] = repo_path; + argv[6] = (char *) NULL; + */ + + if (fexecve(fd, __DECONST(char **, argv), NULL) == -1) { fprintf(stderr, "%s: %s: %s\n", getprogname(), path, strerror(errno)); _exit(1); diff --git a/lib/reference.c b/lib/reference.c index 106c67f2..b4d9a569 100644 --- a/lib/reference.c +++ b/lib/reference.c @@ -47,6 +47,9 @@ #include "got_lib_object.h" #include "got_lib_lockfile.h" +#include +#include + #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif @@ -165,7 +168,7 @@ parse_ref_line(struct got_reference **ref, const char *name, const char *line) static const struct got_error * parse_ref_file(struct got_reference **ref, const char *name, - const char *absname, const char *abspath, int lock) + int repo_fd, const char *absname, const char *abspath, int lock) { const struct got_error *err = NULL; FILE *f; @@ -173,9 +176,10 @@ parse_ref_file(struct got_reference **ref, const char *name, size_t linesize = 0; ssize_t linelen; struct got_lockfile *lf = NULL; + cap_rights_t rights; if (lock) { - err = got_lockfile_lock(&lf, abspath); + err = got_lockfile_lock(&lf, repo_fd, absname); if (err) { if (err->code == GOT_ERR_ERRNO && errno == ENOENT) err = got_error_not_ref(name); @@ -183,7 +187,14 @@ parse_ref_file(struct got_reference **ref, const char *name, } } - f = fopen(abspath, "rb"); + int fd = openat(repo_fd, absname, 0); + cap_rights_init(&rights, CAP_READ, CAP_FSTAT, CAP_FCNTL); + if (caph_rights_limit(fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + return err; + } + + f = fdopen(fd, "rb"); if (f == NULL) { if (errno != ENOTDIR && errno != ENOENT) err = got_error_from_errno2("fopen", abspath); @@ -193,7 +204,6 @@ parse_ref_file(struct got_reference **ref, const char *name, got_lockfile_unlock(lf); return err; } - linelen = getline(&line, &linesize, f); if (linelen == -1) { if (feof(f)) @@ -250,12 +260,12 @@ is_well_known_ref(const char *refname) } static char * -get_refs_dir_path(struct got_repository *repo, const char *refname) +get_refs_dir_path(const char *refname) { if (is_well_known_ref(refname) || strncmp(refname, "refs/", 5) == 0) - return strdup(got_repo_get_path_git_dir(repo)); + return strdup("."); - return got_repo_get_path_refs(repo); + return got_repo_get_path_refs(); } static int @@ -397,7 +407,7 @@ open_packed_ref(struct got_reference **ref, FILE *f, const char **subdirs, } static const struct got_error * -open_ref(struct got_reference **ref, const char *path_refs, const char *subdir, +open_ref(struct got_reference **ref, int git_dir_fd, const char *path_refs, const char *subdir, const char *name, int lock) { const struct got_error *err = NULL; @@ -424,7 +434,7 @@ open_ref(struct got_reference **ref, const char *path_refs, const char *subdir, } } - err = parse_ref_file(ref, name, absname, path, lock); + err = parse_ref_file(ref, name, git_dir_fd, absname, path, lock); done: if (!ref_is_absolute && !ref_is_well_known) free(absname); @@ -433,7 +443,7 @@ done: } const struct got_error * -got_ref_open(struct got_reference **ref, struct got_repository *repo, +got_ref_open(struct got_reference **ref, int git_dir_fd, const char *refname, int lock) { const struct got_error *err = NULL; @@ -447,27 +457,29 @@ got_ref_open(struct got_reference **ref, struct got_repository *repo, *ref = NULL; - path_refs = get_refs_dir_path(repo, refname); + path_refs = get_refs_dir_path(refname); if (path_refs == NULL) { err = got_error_from_errno2("get_refs_dir_path", refname); goto done; } if (well_known) { - err = open_ref(ref, path_refs, "", refname, lock); + err = open_ref(ref, git_dir_fd, path_refs, "", refname, lock); } else { char *packed_refs_path; FILE *f; /* Search on-disk refs before packed refs! */ for (i = 0; i < nitems(subdirs); i++) { - err = open_ref(ref, path_refs, subdirs[i], refname, + err = open_ref(ref, git_dir_fd, path_refs, subdirs[i], refname, lock); if ((err && err->code != GOT_ERR_NOT_REF) || *ref) goto done; } - packed_refs_path = got_repo_get_path_packed_refs(repo); + printf("CODE BELOW THIS HAS NOT BEEN CAPSIZED\n"); + + packed_refs_path = got_repo_get_path_packed_refs(); if (packed_refs_path == NULL) { err = got_error_from_errno( "got_repo_get_path_packed_refs"); @@ -475,7 +487,8 @@ got_ref_open(struct got_reference **ref, struct got_repository *repo, } if (lock) { - err = got_lockfile_lock(&lf, packed_refs_path); + printf("open NEED TO TEST %s\n", packed_refs_path); + err = got_lockfile_lock(&lf, git_dir_fd, packed_refs_path); if (err) goto done; } @@ -580,7 +593,8 @@ resolve_symbolic_ref(struct got_reference **resolved, struct got_reference *nextref; const struct got_error *err; - err = got_ref_open(&nextref, repo, ref->ref.symref.ref, 0); + err = got_ref_open(&nextref, got_repo_get_path_git_dir_fd(repo), + ref->ref.symref.ref, 0); if (err) return err; @@ -805,7 +819,10 @@ gather_on_disk_refs(struct got_reflist_head *refs, const char *path_refs, if (asprintf(&path_subdir, "%s/%s", path_refs, subdir) == -1) return got_error_from_errno("asprintf"); - d = opendir(path_subdir); + int fd = openat(got_repo_get_path_git_dir_fd(repo), path_subdir, O_DIRECTORY); + if (fd == -1) + goto done; + d = fdopendir(fd); if (d == NULL) goto done; @@ -829,7 +846,8 @@ gather_on_disk_refs(struct got_reflist_head *refs, const char *path_refs, switch (type) { case DT_REG: - err = open_ref(&ref, path_refs, subdir, dent->d_name, + err = open_ref(&ref, got_repo_get_path_git_dir_fd(repo), + path_refs, subdir, dent->d_name, 0); if (err) goto done; @@ -877,12 +895,13 @@ got_ref_list(struct got_reflist_head *refs, struct got_repository *repo, struct got_reflist_entry *new; if (ref_namespace == NULL || ref_namespace[0] == '\0') { - path_refs = get_refs_dir_path(repo, GOT_REF_HEAD); + path_refs = get_refs_dir_path(GOT_REF_HEAD); if (path_refs == NULL) { err = got_error_from_errno("get_refs_dir_path"); goto done; } - err = open_ref(&ref, path_refs, "", GOT_REF_HEAD, 0); + err = open_ref(&ref, got_repo_get_path_git_dir_fd(repo), + path_refs, "", GOT_REF_HEAD, 0); if (err) goto done; err = insert_ref(&new, refs, ref, repo, @@ -894,12 +913,13 @@ got_ref_list(struct got_reflist_head *refs, struct got_repository *repo, } else { /* Try listing a single reference. */ const char *refname = ref_namespace; - path_refs = get_refs_dir_path(repo, refname); + path_refs = get_refs_dir_path(refname); if (path_refs == NULL) { err = got_error_from_errno("get_refs_dir_path"); goto done; } - err = open_ref(&ref, path_refs, "", refname, 0); + err = open_ref(&ref, got_repo_get_path_git_dir_fd(repo), + path_refs, "", refname, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; @@ -940,7 +960,7 @@ got_ref_list(struct got_reflist_head *refs, struct got_repository *repo, /* Gather on-disk refs before parsing packed-refs. */ free(path_refs); - path_refs = get_refs_dir_path(repo, ""); + path_refs = get_refs_dir_path(""); if (path_refs == NULL) { err = got_error_from_errno("get_refs_dir_path"); goto done; @@ -955,13 +975,14 @@ got_ref_list(struct got_reflist_head *refs, struct got_repository *repo, * The packed-refs file may contain redundant entries, in which * case on-disk refs take precedence. */ - packed_refs_path = got_repo_get_path_packed_refs(repo); + packed_refs_path = got_repo_get_path_packed_refs(); if (packed_refs_path == NULL) { err = got_error_from_errno("got_repo_get_path_packed_refs"); goto done; } - f = fopen(packed_refs_path, "r"); + int fd = openat(got_repo_get_path_git_dir_fd(repo), packed_refs_path, O_RDONLY); + f = fdopen(fd, "r"); free(packed_refs_path); if (f) { char *line; @@ -1078,8 +1099,9 @@ got_ref_write(struct got_reference *ref, struct got_repository *repo) FILE *f = NULL; size_t n; struct stat sb; + int git_fd = got_repo_get_path_git_dir_fd(repo); - path_refs = get_refs_dir_path(repo, name); + path_refs = get_refs_dir_path(name); if (path_refs == NULL) { err = got_error_from_errno2("get_refs_dir_path", name); goto done; @@ -1090,7 +1112,7 @@ got_ref_write(struct got_reference *ref, struct got_repository *repo) goto done; } - err = got_opentemp_named(&tmppath, &f, path); + err = got_opentemp_named(git_fd, &tmppath, &f, path); if (err) { char *parent; if (!(err->code == GOT_ERR_ERRNO && errno == ENOENT)) @@ -1098,11 +1120,11 @@ got_ref_write(struct got_reference *ref, struct got_repository *repo) err = got_path_dirname(&parent, path); if (err) goto done; - err = got_path_mkdir(parent); + err = got_path_mkdirat(git_fd, parent); free(parent); if (err) goto done; - err = got_opentemp_named(&tmppath, &f, path); + err = got_opentemp_named(git_fd, &tmppath, &f, path); if (err) goto done; } @@ -1128,14 +1150,14 @@ got_ref_write(struct got_reference *ref, struct got_repository *repo) } if (ref->lf == NULL) { - err = got_lockfile_lock(&lf, path); + err = got_lockfile_lock(&lf, git_fd, path); if (err) goto done; } /* XXX: check if old content matches our expectations? */ - if (stat(path, &sb) != 0) { + if (fstatat(git_fd, path, &sb, 0) != 0) { if (errno != ENOENT) { err = got_error_from_errno2("stat", path); goto done; @@ -1143,15 +1165,15 @@ got_ref_write(struct got_reference *ref, struct got_repository *repo) sb.st_mode = GOT_DEFAULT_FILE_MODE; } - if (rename(tmppath, path) != 0) { - err = got_error_from_errno3("rename", tmppath, path); + if (renameat(git_fd, tmppath, git_fd, path) != 0) { + err = got_error_from_errno3("renameat", tmppath, path); goto done; } free(tmppath); tmppath = NULL; - if (chmod(path, sb.st_mode) != 0) { - err = got_error_from_errno2("chmod", path); + if (fchmodat(git_fd, path, sb.st_mode, 0) != 0) { + err = got_error_from_errno2("fchmodat", path); goto done; } done: @@ -1164,8 +1186,8 @@ done: free(path_refs); free(path); if (tmppath) { - if (unlink(tmppath) != 0 && err == NULL) - err = got_error_from_errno2("unlink", tmppath); + if (unlinkat(git_fd, tmppath, 0) != 0 && err == NULL) + err = got_error_from_errno2("unlinkat", tmppath); free(tmppath); } return err ? err : unlock_err; @@ -1187,16 +1209,18 @@ delete_packed_ref(struct got_reference *delref, struct got_repository *repo) SIMPLEQ_INIT(&refs); - packed_refs_path = got_repo_get_path_packed_refs(repo); + packed_refs_path = got_repo_get_path_packed_refs(); if (packed_refs_path == NULL) return got_error_from_errno("got_repo_get_path_packed_refs"); - err = got_opentemp_named(&tmppath, &tmpf, packed_refs_path); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &tmppath, &tmpf, packed_refs_path); if (err) goto done; if (delref->lf == NULL) { - err = got_lockfile_lock(&lf, packed_refs_path); + printf("delete NEED TO TEST %s\n", packed_refs_path); + err = got_lockfile_lock(&lf, got_repo_get_path_git_dir_fd(repo), packed_refs_path); if (err) goto done; } @@ -1326,7 +1350,7 @@ delete_loose_ref(struct got_reference *ref, struct got_repository *repo) char *path_refs = NULL, *path = NULL; struct got_lockfile *lf = NULL; - path_refs = get_refs_dir_path(repo, name); + path_refs = get_refs_dir_path(name); if (path_refs == NULL) { err = got_error_from_errno2("get_refs_dir_path", name); goto done; @@ -1338,7 +1362,8 @@ delete_loose_ref(struct got_reference *ref, struct got_repository *repo) } if (ref->lf == NULL) { - err = got_lockfile_lock(&lf, path); + printf("delete loose NEED TO TEST %s\n", path); + err = got_lockfile_lock(&lf, got_repo_get_path_git_dir_fd(repo), path); if (err) goto done; } diff --git a/lib/repository.c b/lib/repository.c index c408233b..924751c7 100644 --- a/lib/repository.c +++ b/lib/repository.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include @@ -46,6 +47,7 @@ #include "got_reference.h" #include "got_repository.h" #include "got_path.h" +#include "got_privsep.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_object.h" @@ -63,6 +65,9 @@ #include "got_lib_repository.h" #include "got_lib_gotconfig.h" +#include +#include + #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif @@ -79,6 +84,17 @@ got_repo_get_path_git_dir(struct got_repository *repo) return repo->path_git_dir; } +int +got_repo_get_path_fd(struct got_repository *repo) +{ + return repo->path_fd; +} + +int +got_repo_get_path_git_dir_fd(struct got_repository *repo) +{ + return repo->path_git_dir_fd; +} const char * got_repo_get_gitconfig_author_name(struct got_repository *repo) { @@ -128,27 +144,27 @@ get_path_git_child(struct got_repository *repo, const char *basename) } char * -got_repo_get_path_objects(struct got_repository *repo) +got_repo_get_path_objects(void) { - return get_path_git_child(repo, GOT_OBJECTS_DIR); + return strdup(GOT_OBJECTS_DIR); } char * -got_repo_get_path_objects_pack(struct got_repository *repo) +got_repo_get_path_objects_pack(void) { - return get_path_git_child(repo, GOT_OBJECTS_PACK_DIR); + return strdup(GOT_OBJECTS_PACK_DIR); } char * -got_repo_get_path_refs(struct got_repository *repo) +got_repo_get_path_refs(void) { - return get_path_git_child(repo, GOT_REFS_DIR); + return strdup(GOT_REFS_DIR); } char * -got_repo_get_path_packed_refs(struct got_repository *repo) +got_repo_get_path_packed_refs(void) { - return get_path_git_child(repo, GOT_PACKED_REFS_FILE); + return strdup(GOT_PACKED_REFS_FILE); } static char * @@ -164,9 +180,9 @@ got_repo_get_path_gitconfig(struct got_repository *repo) } char * -got_repo_get_path_gotconfig(struct got_repository *repo) +got_repo_get_path_gotconfig(void) { - return get_path_git_child(repo, GOT_GOTCONFIG_FILENAME); + return strdup(GOT_GOTCONFIG_FILENAME); } const struct got_gotconfig * @@ -184,46 +200,39 @@ got_repo_get_gitconfig_remotes(int *nremotes, } static int -is_git_repo(struct got_repository *repo) +is_git_repo(int git_fd) { - const char *path_git = got_repo_get_path_git_dir(repo); - char *path_objects = got_repo_get_path_objects(repo); - char *path_refs = got_repo_get_path_refs(repo); - char *path_head = get_path_head(repo); int ret = 0; struct stat sb; struct got_reference *head_ref; - if (lstat(path_git, &sb) == -1) + if (fstat(git_fd, &sb) == -1) goto done; if (!S_ISDIR(sb.st_mode)) goto done; - if (lstat(path_objects, &sb) == -1) + if (fstatat(git_fd, GOT_OBJECTS_DIR, &sb, 0) == -1) goto done; if (!S_ISDIR(sb.st_mode)) goto done; - if (lstat(path_refs, &sb) == -1) + if (fstatat(git_fd, GOT_REFS_DIR, &sb, 0) == -1) goto done; if (!S_ISDIR(sb.st_mode)) goto done; - if (lstat(path_head, &sb) == -1) + if (fstatat(git_fd, GOT_HEAD_FILE, &sb, 0) == -1) goto done; if (!S_ISREG(sb.st_mode)) goto done; /* Check if the HEAD reference can be opened. */ - if (got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0) != NULL) + if (got_ref_open(&head_ref, git_fd, GOT_REF_HEAD, 0) != NULL) goto done; got_ref_close(head_ref); ret = 1; done: - free(path_objects); - free(path_refs); - free(path_head); return ret; } @@ -331,15 +340,77 @@ got_repo_get_cached_tag(struct got_repository *repo, struct got_object_id *id) } const struct got_error * -open_repo(struct got_repository *repo, const char *path) +got_repo_find_git_path(char **path) +{ + const struct got_error *error; + char *parent_path, *repo_path; + int fd, git_dir_fd; + + repo_path = strdup(*path); + if (repo_path == NULL) + return got_error_from_errno("strdup"); + + for (;;) { + /* bare git repository? */ + fd = open(repo_path, O_DIRECTORY); + if (fd == -1) { + error = got_error_from_errno2("open", repo_path); + goto done; + } + if (is_git_repo(fd)) { + close(fd); + break; + } + + /* git repository with working tree? */ + git_dir_fd = openat(fd, GOT_GIT_DIR, O_DIRECTORY); + if (git_dir_fd == -1 && errno != ENOENT) { + error = got_error_from_errno("openat"); + goto done; + } else if (git_dir_fd != -1) { + if (is_git_repo(git_dir_fd)) { + close(git_dir_fd); + close(fd); + break; + } + close(git_dir_fd); + } + + close(fd); + if (repo_path[0] == '/' && repo_path[1] == '\0') { + error = got_error(GOT_ERR_NOT_GIT_REPO); + goto done; + } + error = got_path_dirname(&parent_path, repo_path); + if (error) + goto done; + free(repo_path); + repo_path = parent_path; + } +done: + if (error) { + free(repo_path); + return error; + } + free(*path); + *path = repo_path; + return NULL; +} + +const struct got_error * +open_repo(struct got_repository *repo, int fd, const char *path) { const struct got_error *err = NULL; + cap_rights_t rights; /* bare git repository? */ + repo->path_fd = fd; + repo->path_git_dir_fd = fd; + repo->path_git_dir = strdup(path); if (repo->path_git_dir == NULL) return got_error_from_errno("strdup"); - if (is_git_repo(repo)) { + if (is_git_repo(repo->path_git_dir_fd)) { repo->path = strdup(repo->path_git_dir); if (repo->path == NULL) { err = got_error_from_errno("strdup"); @@ -351,11 +422,22 @@ open_repo(struct got_repository *repo, const char *path) /* git repository with working tree? */ free(repo->path_git_dir); repo->path_git_dir = NULL; + + repo->path_fd = fd; + repo->path_git_dir_fd = openat(fd, GOT_GIT_DIR, O_DIRECTORY | O_CREAT); + + cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET, CAP_MKDIRAT, + CAP_CREATE, CAP_READ, CAP_WRITE, CAP_UNLINKAT, CAP_FLOCK, CAP_FCHMOD, CAP_MMAP_R); + if (caph_rights_limit(repo->path_git_dir_fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + goto done; + } + if (asprintf(&repo->path_git_dir, "%s/%s", path, GOT_GIT_DIR) == -1) { err = got_error_from_errno("asprintf"); goto done; } - if (is_git_repo(repo)) { + if (is_git_repo(repo->path_git_dir_fd)) { repo->path = strdup(path); if (repo->path == NULL) { err = got_error_from_errno("strdup"); @@ -380,13 +462,15 @@ parse_gitconfig_file(int *gitconfig_repository_format_version, char **gitconfig_author_name, char **gitconfig_author_email, struct got_remote_repo **remotes, int *nremotes, char **gitconfig_owner, - const char *gitconfig_path) + int git_fd, const char *gitconfig_path) { const struct got_error *err = NULL, *child_err = NULL; int fd = -1; + int pd = -1; int imsg_fds[2] = { -1, -1 }; pid_t pid; struct imsgbuf *ibuf; + cap_rights_t rights; *gitconfig_repository_format_version = 0; *gitconfig_author_name = NULL; @@ -398,13 +482,17 @@ parse_gitconfig_file(int *gitconfig_repository_format_version, if (gitconfig_owner) *gitconfig_owner = NULL; - fd = open(gitconfig_path, O_RDONLY); + fd = openat(git_fd, gitconfig_path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) return NULL; return got_error_from_errno2("open", gitconfig_path); } + cap_rights_init(&rights, CAP_READ, CAP_FSTAT); + if (caph_rights_limit(fd, &rights) < 0) + return got_error_from_errno("caph_rights_limit"); + ibuf = calloc(1, sizeof(*ibuf)); if (ibuf == NULL) { err = got_error_from_errno("calloc"); @@ -416,7 +504,7 @@ parse_gitconfig_file(int *gitconfig_repository_format_version, goto done; } - pid = fork(); + pid = pdfork(&pd, 0); if (pid == -1) { err = got_error_from_errno("fork"); goto done; @@ -485,7 +573,7 @@ parse_gitconfig_file(int *gitconfig_repository_format_version, imsg_clear(ibuf); err = got_privsep_send_stop(imsg_fds[0]); - child_err = got_privsep_wait_for_child(pid); + child_err = got_privsep_wait_for_child(pd); if (child_err && err == NULL) err = child_err; done: @@ -503,32 +591,33 @@ static const struct got_error * read_gitconfig(struct got_repository *repo, const char *global_gitconfig_path) { const struct got_error *err = NULL; - char *repo_gitconfig_path = NULL; + int git_fd; if (global_gitconfig_path) { /* Read settings from ~/.gitconfig. */ int dummy_repo_version; + printf("PARSE_GITCONFIG_FILE with global gitconfig path BROKEN\n"); err = parse_gitconfig_file(&dummy_repo_version, &repo->global_gitconfig_author_name, &repo->global_gitconfig_author_email, - NULL, NULL, NULL, global_gitconfig_path); + NULL, NULL, NULL, -1, global_gitconfig_path); if (err) return err; } /* Read repository's .git/config file. */ - repo_gitconfig_path = got_repo_get_path_gitconfig(repo); - if (repo_gitconfig_path == NULL) - return got_error_from_errno("got_repo_get_path_gitconfig"); + git_fd = got_repo_get_path_git_dir_fd(repo); + if (git_fd == -1) + return got_error_from_errno("got_repo_get_path_git_dir_fd"); + GOT_GITCONFIG; err = parse_gitconfig_file(&repo->gitconfig_repository_format_version, &repo->gitconfig_author_name, &repo->gitconfig_author_email, &repo->gitconfig_remotes, &repo->ngitconfig_remotes, - &repo->gitconfig_owner, repo_gitconfig_path); + &repo->gitconfig_owner, git_fd, GOT_GITCONFIG); if (err) goto done; done: - free(repo_gitconfig_path); return err; } @@ -537,18 +626,22 @@ read_gotconfig(struct got_repository *repo) { const struct got_error *err = NULL; char *gotconfig_path; + int git_fd; - gotconfig_path = got_repo_get_path_gotconfig(repo); + gotconfig_path = got_repo_get_path_gotconfig(); if (gotconfig_path == NULL) return got_error_from_errno("got_repo_get_path_gotconfig"); + git_fd = got_repo_get_path_git_dir_fd(repo); + if (git_fd == -1) + return got_error_from_errno("got_repo_get_path_git_dir_fd"); - err = got_gotconfig_read(&repo->gotconfig, gotconfig_path); + err = got_gotconfig_read(&repo->gotconfig, gotconfig_path, git_fd); free(gotconfig_path); return err; } const struct got_error * -got_repo_open(struct got_repository **repop, const char *path, +got_repo_open(struct got_repository **repop, int repo_fd, const char *path, const char *global_gitconfig_path) { struct got_repository *repo = NULL; @@ -558,12 +651,7 @@ got_repo_open(struct got_repository **repop, const char *path, *repop = NULL; - if (got_path_is_absolute(path)) - abspath = strdup(path); - else - abspath = got_path_get_absolute(path); - if (abspath == NULL) - return got_error_path(path, GOT_ERR_BAD_PATH); + abspath = strdup(path); repo = calloc(1, sizeof(*repo)); if (repo == NULL) { @@ -594,30 +682,15 @@ got_repo_open(struct got_repository **repop, const char *path, if (err) goto done; - repo_path = realpath(abspath, NULL); + repo_path = strdup(abspath); if (repo_path == NULL) { err = got_error_from_errno2("realpath", abspath); goto done; } - for (;;) { - char *parent_path; - - err = open_repo(repo, repo_path); - if (err == NULL) - break; - if (err->code != GOT_ERR_NOT_GIT_REPO) - goto done; - if (repo_path[0] == '/' && repo_path[1] == '\0') { - err = got_error(GOT_ERR_NOT_GIT_REPO); - goto done; - } - err = got_path_dirname(&parent_path, repo_path); - if (err) - goto done; - free(repo_path); - repo_path = parent_path; - } + err = open_repo(repo, repo_fd, repo_path); + if (err != NULL && err->code != GOT_ERR_NOT_GIT_REPO) + goto done; err = read_gotconfig(repo); if (err) @@ -626,6 +699,7 @@ got_repo_open(struct got_repository **repop, const char *path, err = read_gitconfig(repo, global_gitconfig_path); if (err) goto done; + if (repo->gitconfig_repository_format_version != 0) err = got_error_path(path, GOT_ERR_GIT_REPO_FORMAT); done: @@ -870,6 +944,7 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx, struct dirent *dent; char *path_packidx; size_t i; + cap_rights_t rights; /* Search pack index cache. */ for (i = 0; i < nitems(repo->packidx_cache); i++) { @@ -893,11 +968,17 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx, } /* No luck. Search the filesystem. */ - path_packdir = got_repo_get_path_objects_pack(repo); + path_packdir = got_repo_get_path_objects_pack(); if (path_packdir == NULL) return got_error_from_errno("got_repo_get_path_objects_pack"); - packdir = opendir(path_packdir); + int fd = openat(got_repo_get_path_git_dir_fd(repo), path_packdir, O_DIRECTORY); + packdir = fdopendir(fd); + + cap_rights_init(&rights, CAP_FSTAT, CAP_READ, CAP_UNLINKAT, CAP_MMAP_R); + if (caph_rights_limit(fd, &rights) < 0) + return got_error_from_errno("caph_rights_limit"); + if (packdir == NULL) { if (errno == ENOENT) err = got_error_no_obj(id); @@ -912,9 +993,9 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx, if (!is_packidx_filename(dent->d_name, dent->d_namlen)) continue; - if (asprintf(&path_packidx, "%s/%s", path_packdir, - dent->d_name) == -1) { - err = got_error_from_errno("asprintf"); + path_packidx = strdup(dent->d_name); + if (path_packidx == NULL) { + err = got_error_from_errno("strdup"); goto done; } @@ -932,7 +1013,7 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx, continue; /* already searched */ } - err = got_packidx_open(packidx, path_packidx, 0); + err = got_packidx_open(packidx, fd, path_packidx, 0); if (err) { free(path_packidx); goto done; @@ -952,7 +1033,7 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx, err = got_error_no_obj(id); done: - free(path_packdir); + //free(path_packdir); if (packdir && closedir(packdir) != 0 && err == NULL) err = got_error_from_errno("closedir"); return err; @@ -981,13 +1062,17 @@ read_packfile_hdr(int fd, struct got_packidx *packidx) } static const struct got_error * -open_packfile(int *fd, const char *path_packfile, struct got_packidx *packidx) +open_packfile(int *fd, int packdir_fd, const char *path_packfile, struct got_packidx *packidx) { const struct got_error *err = NULL; + cap_rights_t rights; - *fd = open(path_packfile, O_RDONLY | O_NOFOLLOW); + *fd = openat(packdir_fd, path_packfile, O_RDONLY | O_NOFOLLOW); if (*fd == -1) - return got_error_from_errno2("open", path_packfile); + return got_error_from_errno2("openat", path_packfile); + cap_rights_init(&rights, CAP_READ, CAP_FSTAT, CAP_MMAP_R); + if (caph_rights_limit(*fd, &rights) < 0) + return got_error_from_errno("caph_rights_limit"); if (packidx) { err = read_packfile_hdr(*fd, packidx); @@ -1008,6 +1093,14 @@ got_repo_cache_pack(struct got_pack **packp, struct got_repository *repo, struct got_pack *pack = NULL; struct stat sb; size_t i; + cap_rights_t rights; + + int fd = openat(got_repo_get_path_git_dir_fd(repo), GOT_OBJECTS_PACK_DIR, O_DIRECTORY); + if (fd == -1) + return got_error_from_errno2("openat", GOT_OBJECTS_PACK_DIR); + cap_rights_init(&rights, CAP_FSTAT, CAP_READ, CAP_WRITE, CAP_UNLINKAT, CAP_MMAP_R); + if (caph_rights_limit(fd, &rights) < 0) + return got_error_from_errno("caph_rights_limit"); if (packp) *packp = NULL; @@ -1037,7 +1130,7 @@ got_repo_cache_pack(struct got_pack **packp, struct got_repository *repo, goto done; } - err = open_packfile(&pack->fd, path_packfile, packidx); + err = open_packfile(&pack->fd, fd, path_packfile, packidx); if (err) goto done; @@ -1089,7 +1182,7 @@ got_repo_get_cached_pack(struct got_repository *repo, const char *path_packfile) } const struct got_error * -got_repo_init(const char *repo_path) +got_repo_init(const char *repo_path, int fd) { const struct got_error *err = NULL; const char *dirnames[] = { @@ -1107,37 +1200,24 @@ got_repo_init(const char *repo_path) char *path; size_t i; - if (!got_path_dir_is_empty(repo_path)) + if (!got_path_dir_is_empty(fd)) return got_error(GOT_ERR_DIR_NOT_EMPTY); for (i = 0; i < nitems(dirnames); i++) { - if (asprintf(&path, "%s/%s", repo_path, dirnames[i]) == -1) { - return got_error_from_errno("asprintf"); + if (mkdirat(fd, dirnames[i], GOT_DEFAULT_DIR_MODE) == -1) { + return got_error_from_errno("mkdirat"); } - err = got_path_mkdir(path); - free(path); - if (err) - return err; } - if (asprintf(&path, "%s/%s", repo_path, "description") == -1) - return got_error_from_errno("asprintf"); - err = got_path_create_file(path, description_str); - free(path); + err = got_path_create_file(fd, "description", description_str); if (err) return err; - if (asprintf(&path, "%s/%s", repo_path, GOT_HEAD_FILE) == -1) - return got_error_from_errno("asprintf"); - err = got_path_create_file(path, headref_str); - free(path); + err = got_path_create_file(fd, GOT_HEAD_FILE, headref_str); if (err) return err; - if (asprintf(&path, "%s/%s", repo_path, "config") == -1) - return got_error_from_errno("asprintf"); - err = got_path_create_file(path, gitconfig_str); - free(path); + err = got_path_create_file(fd, "config", gitconfig_str); if (err) return err; @@ -1157,14 +1237,20 @@ match_packed_object(struct got_object_id **unique_id, SIMPLEQ_INIT(&matched_ids); - path_packdir = got_repo_get_path_objects_pack(repo); + path_packdir = got_repo_get_path_objects_pack(); if (path_packdir == NULL) return got_error_from_errno("got_repo_get_path_objects_pack"); - packdir = opendir(path_packdir); + int fd = openat(got_repo_get_path_git_dir_fd(repo), path_packdir, O_DIRECTORY); + if (fd == -1) { + if (errno != ENOENT) + err = got_error_from_errno2("openat", path_packdir); + goto done; + } + packdir = fdopendir(fd); if (packdir == NULL) { if (errno != ENOENT) - err = got_error_from_errno2("opendir", path_packdir); + err = got_error_from_errno2("fdopendir", path_packdir); goto done; } @@ -1176,13 +1262,13 @@ match_packed_object(struct got_object_id **unique_id, if (!is_packidx_filename(dent->d_name, dent->d_namlen)) continue; - if (asprintf(&path_packidx, "%s/%s", path_packdir, - dent->d_name) == -1) { - err = got_error_from_errno("asprintf"); + path_packidx = strdup(dent->d_name); + if (path_packidx == NULL) { + err = got_error_from_errno("strdup"); break; } - err = got_packidx_open(&packidx, path_packidx, 0); + err = got_packidx_open(&packidx, fd, path_packidx, 0); free(path_packidx); if (err) break; @@ -1249,13 +1335,18 @@ match_loose_object(struct got_object_id **unique_id, const char *path_objects, goto done; } - dir = opendir(path); - if (dir == NULL) { + int fd = openat(got_repo_get_path_git_dir_fd(repo), path, O_DIRECTORY); + if (fd == -1) { if (errno == ENOENT) { err = NULL; goto done; } - err = got_error_from_errno2("opendir", path); + err = got_error_from_errno2("openat", path); + goto done; + } + dir = fdopendir(fd); + if (dir == NULL) { + err = got_error_from_errno2("fdopendir", path); goto done; } while ((dent = readdir(dir)) != NULL) { @@ -1324,7 +1415,7 @@ got_repo_match_object_id_prefix(struct got_object_id **id, const char *id_str_prefix, int obj_type, struct got_repository *repo) { const struct got_error *err = NULL; - char *path_objects = got_repo_get_path_objects(repo); + char *path_objects = got_repo_get_path_objects(); char *object_dir = NULL; size_t len; int i; diff --git a/lib/worktree.c b/lib/worktree.c index 3ee4e0d5..61bd58c8 100644 --- a/lib/worktree.c +++ b/lib/worktree.c @@ -59,6 +59,9 @@ #include "got_lib_diff.h" #include "got_lib_gotconfig.h" +#include +#include + #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif @@ -67,34 +70,35 @@ #define GOT_MERGE_LABEL_BASE "3-way merge base" static const struct got_error * -create_meta_file(const char *path_got, const char *name, const char *content) +create_meta_file(int worktree_fd, const char *name, const char *content) { const struct got_error *err = NULL; char *path; - if (asprintf(&path, "%s/%s", path_got, name) == -1) + if (asprintf(&path, "%s/%s", GOT_WORKTREE_GOT_DIR, name) == -1) return got_error_from_errno("asprintf"); - err = got_path_create_file(path, content); + err = got_path_create_file(worktree_fd, path, content); free(path); return err; } static const struct got_error * -update_meta_file(const char *path_got, const char *name, const char *content) +update_meta_file(int worktree_fd, const char *name, const char *content) { const struct got_error *err = NULL; FILE *tmpfile = NULL; char *tmppath = NULL; char *path = NULL; - if (asprintf(&path, "%s/%s", path_got, name) == -1) { + if (asprintf(&path, "%s/%s", GOT_WORKTREE_GOT_DIR, name) == -1) { err = got_error_from_errno("asprintf"); path = NULL; goto done; } - err = got_opentemp_named(&tmppath, &tmpfile, path); + + err = got_opentemp_named(worktree_fd, &tmppath, &tmpfile, path); if (err) goto done; @@ -106,9 +110,9 @@ update_meta_file(const char *path_got, const char *name, const char *content) } } - if (rename(tmppath, path) != 0) { + if (renameat(worktree_fd, tmppath, worktree_fd, path) != 0) { err = got_error_from_errno3("rename", tmppath, path); - unlink(tmppath); + unlinkat(worktree_fd, tmppath, 0); goto done; } @@ -120,13 +124,14 @@ done: } static const struct got_error * -read_meta_file(char **content, const char *path_got, const char *name) +read_meta_file(char **content, int worktree_fd, const char *path_got, const char *name) { const struct got_error *err = NULL; char *path; int fd = -1; ssize_t n; struct stat sb; + cap_rights_t rights; *content = NULL; @@ -136,7 +141,7 @@ read_meta_file(char **content, const char *path_got, const char *name) goto done; } - fd = open(path, O_RDONLY | O_NOFOLLOW); + fd = openat(worktree_fd, path, O_RDONLY | O_NOFOLLOW); if (fd == -1) { if (errno == ENOENT) err = got_error_path(path, GOT_ERR_WORKTREE_META); @@ -144,6 +149,13 @@ read_meta_file(char **content, const char *path_got, const char *name) err = got_error_from_errno2("open", path); goto done; } + + cap_rights_init(&rights, CAP_FLOCK, CAP_FSTAT, CAP_READ); + if (caph_rights_limit(fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + goto done; + } + if (flock(fd, LOCK_SH | LOCK_NB) == -1) { err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) : got_error_from_errno2("flock", path)); @@ -184,7 +196,7 @@ done: } static const struct got_error * -write_head_ref(const char *path_got, struct got_reference *head_ref) +write_head_ref(int worktree_fd, struct got_reference *head_ref) { const struct got_error *err = NULL; char *refstr = NULL; @@ -198,13 +210,13 @@ write_head_ref(const char *path_got, struct got_reference *head_ref) if (refstr == NULL) return got_error_from_errno("strdup"); } - err = update_meta_file(path_got, GOT_WORKTREE_HEAD_REF, refstr); + err = update_meta_file(worktree_fd, GOT_WORKTREE_HEAD_REF, refstr); free(refstr); return err; } const struct got_error * -got_worktree_init(const char *path, struct got_reference *head_ref, +got_worktree_init(int fd, const char *path, struct got_reference *head_ref, const char *prefix, struct got_repository *repo) { const struct got_error *err = NULL; @@ -237,53 +249,48 @@ got_worktree_init(const char *path, struct got_reference *head_ref, return got_error_from_errno("asprintf"); } - /* Create top-level directory (may already exist). */ - if (mkdir(path, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) { - err = got_error_from_errno2("mkdir", path); - goto done; - } - /* Create .got directory (may already exist). */ if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) { err = got_error_from_errno("asprintf"); goto done; } - if (mkdir(path_got, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) { + if (mkdirat(fd, GOT_WORKTREE_GOT_DIR, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) { err = got_error_from_errno2("mkdir", path_got); goto done; } /* Create an empty lock file. */ - err = create_meta_file(path_got, GOT_WORKTREE_LOCK, NULL); + err = create_meta_file(fd, GOT_WORKTREE_LOCK, NULL); if (err) goto done; /* Create an empty file index. */ - err = create_meta_file(path_got, GOT_WORKTREE_FILE_INDEX, NULL); + err = create_meta_file(fd, GOT_WORKTREE_FILE_INDEX, NULL); if (err) goto done; /* Write the HEAD reference. */ - err = write_head_ref(path_got, head_ref); + err = write_head_ref(fd, head_ref); if (err) goto done; + err = write_head_ref(fd, head_ref); /* Record our base commit. */ err = got_object_id_str(&basestr, commit_id); if (err) goto done; - err = create_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, basestr); + err = create_meta_file(fd, GOT_WORKTREE_BASE_COMMIT, basestr); if (err) goto done; /* Store path to repository. */ - err = create_meta_file(path_got, GOT_WORKTREE_REPOSITORY, + err = create_meta_file(fd, GOT_WORKTREE_REPOSITORY, got_repo_get_path(repo)); if (err) goto done; /* Store in-repository path prefix. */ - err = create_meta_file(path_got, GOT_WORKTREE_PATH_PREFIX, + err = create_meta_file(fd, GOT_WORKTREE_PATH_PREFIX, absprefix ? absprefix : prefix); if (err) goto done; @@ -299,7 +306,7 @@ got_worktree_init(const char *path, struct got_reference *head_ref, err = got_error_uuid(uuid_status, "uuid_to_string"); goto done; } - err = create_meta_file(path_got, GOT_WORKTREE_UUID, uuidstr); + err = create_meta_file(fd, GOT_WORKTREE_UUID, uuidstr); if (err) goto done; @@ -308,7 +315,7 @@ got_worktree_init(const char *path, struct got_reference *head_ref, err = got_error_from_errno("asprintf"); goto done; } - err = create_meta_file(path_got, GOT_WORKTREE_FORMAT, formatstr); + err = create_meta_file(fd, GOT_WORKTREE_FORMAT, formatstr); if (err) goto done; @@ -323,7 +330,7 @@ done: } static const struct got_error * -open_worktree(struct got_worktree **worktree, const char *path) +open_worktree(struct got_worktree **worktree, int worktree_fd, const char *path, int repo_fd) { const struct got_error *err = NULL; char *path_got; @@ -335,10 +342,11 @@ open_worktree(struct got_worktree **worktree, const char *path) const char *errstr; struct got_repository *repo = NULL; uint32_t uuid_status; + cap_rights_t rights; *worktree = NULL; - if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) { + if (asprintf(&path_got, "%s", GOT_WORKTREE_GOT_DIR) == -1) { err = got_error_from_errno("asprintf"); path_got = NULL; goto done; @@ -350,14 +358,20 @@ open_worktree(struct got_worktree **worktree, const char *path) goto done; } - fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK); + fd = openat(worktree_fd, path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK); if (fd == -1) { err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) : got_error_from_errno2("open", path_lock)); goto done; } - err = read_meta_file(&formatstr, path_got, GOT_WORKTREE_FORMAT); + cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FLOCK); + if (caph_rights_limit(fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + goto done; + } + + err = read_meta_file(&formatstr, worktree_fd, path_got, GOT_WORKTREE_FORMAT); if (err) goto done; @@ -379,27 +393,27 @@ open_worktree(struct got_worktree **worktree, const char *path) } (*worktree)->lockfd = -1; - (*worktree)->root_path = realpath(path, NULL); + (*worktree)->root_path = strdup(path); if ((*worktree)->root_path == NULL) { - err = got_error_from_errno2("realpath", path); + err = got_error_from_errno2("strdup", path); goto done; } - err = read_meta_file(&(*worktree)->repo_path, path_got, + err = read_meta_file(&(*worktree)->repo_path, worktree_fd, path_got, GOT_WORKTREE_REPOSITORY); if (err) goto done; - err = read_meta_file(&(*worktree)->path_prefix, path_got, + err = read_meta_file(&(*worktree)->path_prefix, worktree_fd, path_got, GOT_WORKTREE_PATH_PREFIX); if (err) goto done; - err = read_meta_file(&base_commit_id_str, path_got, + err = read_meta_file(&base_commit_id_str, worktree_fd, path_got, GOT_WORKTREE_BASE_COMMIT); if (err) goto done; - err = read_meta_file(&uuidstr, path_got, GOT_WORKTREE_UUID); + err = read_meta_file(&uuidstr, worktree_fd, path_got, GOT_WORKTREE_UUID); if (err) goto done; uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); @@ -408,7 +422,7 @@ open_worktree(struct got_worktree **worktree, const char *path) goto done; } - err = got_repo_open(&repo, (*worktree)->repo_path, NULL); + err = got_repo_open(&repo, repo_fd, (*worktree)->repo_path, NULL); if (err) goto done; @@ -417,7 +431,7 @@ open_worktree(struct got_worktree **worktree, const char *path) if (err) goto done; - err = read_meta_file(&(*worktree)->head_ref_name, path_got, + err = read_meta_file(&(*worktree)->head_ref_name, worktree_fd, path_got, GOT_WORKTREE_HEAD_REF); if (err) goto done; @@ -429,8 +443,25 @@ open_worktree(struct got_worktree **worktree, const char *path) goto done; } + int got_dir_fd = openat(worktree_fd, GOT_WORKTREE_GOT_DIR, O_DIRECTORY); + if (got_dir_fd == -1) { + err = got_error_from_errno2("openat", GOT_WORKTREE_GOT_DIR); + goto done; + } + + cap_rights_init(&rights, CAP_LOOKUP, CAP_READ); + if (caph_rights_limit(got_dir_fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + goto done; + } + err = got_gotconfig_read(&(*worktree)->gotconfig, - (*worktree)->gotconfig_path); + GOT_GOTCONFIG_FILENAME, got_dir_fd); + + close(got_dir_fd); + + (*worktree)->root_fd = worktree_fd; + (*worktree)->repo_fd = repo_fd; done: if (repo) got_repo_close(repo); @@ -452,7 +483,7 @@ done: } const struct got_error * -got_worktree_open(struct got_worktree **worktree, const char *path) +got_worktree_open(struct got_worktree **worktree, int worktree_fd, const char *path, int repo_fd) { const struct got_error *err = NULL; char *worktree_path; @@ -464,7 +495,7 @@ got_worktree_open(struct got_worktree **worktree, const char *path) for (;;) { char *parent_path; - err = open_worktree(worktree, worktree_path); + err = open_worktree(worktree, worktree_fd, worktree_path, repo_fd); if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { free(worktree_path); return err; @@ -569,6 +600,7 @@ got_worktree_set_head_ref(struct got_worktree *worktree, goto done; } + printf("WRITE_HEAD_REF - BROKEN\n"); err = write_head_ref(path_got, head_ref); if (err) goto done; @@ -595,14 +627,6 @@ got_worktree_set_base_commit_id(struct got_worktree *worktree, const struct got_error *err; struct got_object *obj = NULL; char *id_str = NULL; - char *path_got = NULL; - - if (asprintf(&path_got, "%s/%s", worktree->root_path, - GOT_WORKTREE_GOT_DIR) == -1) { - err = got_error_from_errno("asprintf"); - path_got = NULL; - goto done; - } err = got_object_open(&obj, repo, commit_id); if (err) @@ -617,7 +641,7 @@ got_worktree_set_base_commit_id(struct got_worktree *worktree, err = got_object_id_str(&id_str, commit_id); if (err) goto done; - err = update_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, id_str); + err = update_meta_file(worktree->root_fd, GOT_WORKTREE_BASE_COMMIT, id_str); if (err) goto done; @@ -631,7 +655,6 @@ done: if (obj) got_object_close(obj); free(id_str); - free(path_got); return err; } @@ -655,23 +678,18 @@ static const struct got_error * add_dir_on_disk(struct got_worktree *worktree, const char *path) { const struct got_error *err = NULL; - char *abspath; - - if (asprintf(&abspath, "%s/%s", worktree->root_path, path) == -1) - return got_error_from_errno("asprintf"); - err = got_path_mkdir(abspath); + err = got_path_mkdirat(worktree->root_fd, path); if (err && err->code == GOT_ERR_ERRNO && errno == EEXIST) { struct stat sb; err = NULL; - if (lstat(abspath, &sb) == -1) { - err = got_error_from_errno2("lstat", abspath); + if (fstatat(worktree->root_fd, path, &sb, 0) == -1) { + err = got_error_from_errno2("fstatat", path); } else if (!S_ISDIR(sb.st_mode)) { /* TODO directory is obstructed; do something */ - err = got_error_path(abspath, GOT_ERR_FILE_OBSTRUCTED); + err = got_error_path(path, GOT_ERR_FILE_OBSTRUCTED); } } - free(abspath); return err; } @@ -810,7 +828,8 @@ merge_file(int *local_changes_subsumed, struct got_worktree *worktree, goto done; } - err = got_opentemp_named(&blob_orig_path, &f_orig, base_path); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &blob_orig_path, &f_orig, base_path); if (err) goto done; if (blob_orig) { @@ -842,7 +861,8 @@ merge_file(int *local_changes_subsumed, struct got_worktree *worktree, base_path = NULL; goto done; } - err = got_opentemp_named(&symlink_path, &symlinkf, base_path); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &symlink_path, &symlinkf, base_path); if (err) goto done; target_len = readlink(ondisk_path, target_path, @@ -966,7 +986,8 @@ install_symlink_conflict(const char *deriv_target, goto done; } - err = got_opentemp_named(&path, &f, "got-symlink-conflict"); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &path, &f, "got-symlink-conflict"); if (err) goto done; @@ -1141,7 +1162,8 @@ merge_blob(int *local_changes_subsumed, struct got_worktree *worktree, goto done; } - err = got_opentemp_named(&blob_deriv_path, &f_deriv, base_path); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &blob_deriv_path, &f_deriv, base_path); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_deriv, @@ -1178,7 +1200,7 @@ done: static const struct got_error * create_fileindex_entry(struct got_fileindex_entry **new_iep, struct got_fileindex *fileindex, struct got_object_id *base_commit_id, - const char *ondisk_path, const char *path, struct got_object_id *blob_id) + const char *ondisk_path, int wt_fd, const char *path, struct got_object_id *blob_id) { const struct got_error *err = NULL; struct got_fileindex_entry *new_ie; @@ -1189,7 +1211,7 @@ create_fileindex_entry(struct got_fileindex_entry **new_iep, if (err) return err; - err = got_fileindex_entry_update(new_ie, ondisk_path, + err = got_fileindex_entry_update(new_ie, wt_fd, path, blob_id->sha1, base_commit_id->sha1, 1); if (err) goto done; @@ -1472,8 +1494,9 @@ install_blob(struct got_worktree *worktree, const char *ondisk_path, size_t len, hdrlen; int update = 0; char *tmppath = NULL; + cap_rights_t rights; - fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, + fd = openat(worktree->root_fd, path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, GOT_DEFAULT_FILE_MODE); if (fd == -1) { if (errno == ENOENT) { @@ -1513,6 +1536,13 @@ install_blob(struct got_worktree *worktree, const char *ondisk_path, return got_error_from_errno2("open", ondisk_path); } + cap_rights_init(&rights, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET, CAP_UNLINKAT, + CAP_READ, CAP_WRITE, CAP_FSYNC); + if (caph_rights_limit(fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + goto done; + } + if (progress_cb) { if (restoring_missing_file) err = (*progress_cb)(progress_arg, GOT_STATUS_MISSING, @@ -1553,17 +1583,17 @@ install_blob(struct got_worktree *worktree, const char *ondisk_path, } if (update) { - if (rename(tmppath, ondisk_path) != 0) { + if (renameat(fd, tmppath, fd, ondisk_path) != 0) { err = got_error_from_errno3("rename", tmppath, ondisk_path); - unlink(tmppath); + unlinkat(fd, tmppath, 0); goto done; } } - if (chmod(ondisk_path, - get_ondisk_perms(te_mode & S_IXUSR, st_mode)) == -1) { - err = got_error_from_errno2("chmod", ondisk_path); + if (fchmodat(worktree->root_fd, path, + get_ondisk_perms(te_mode & S_IXUSR, st_mode), 0) == -1) { + err = got_error_from_errno2("fchmodat", path); goto done; } @@ -1856,12 +1886,13 @@ done: * we had to run a full content comparison to find out. */ static const struct got_error * -sync_timestamps(char *ondisk_path, unsigned char status, +sync_timestamps(int wt_fd, const char *path, unsigned char status, struct got_fileindex_entry *ie, struct stat *sb) { - if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb)) - return got_fileindex_entry_update(ie, ondisk_path, + if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb)) { + return got_fileindex_entry_update(ie, wt_fd, path, ie->blob_sha1, ie->commit_sha1, 1); + } return NULL; } @@ -1887,7 +1918,7 @@ update_blob(struct got_worktree *worktree, err = got_error_path(ie->path, GOT_ERR_FILE_STAGED); goto done; } - err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, + err = get_file_status(&status, &sb, ie, ondisk_path, worktree->root_fd, path, repo); if (err) goto done; @@ -1913,7 +1944,7 @@ update_blob(struct got_worktree *worktree, if (got_fileindex_entry_has_commit(ie) && memcmp(ie->commit_sha1, worktree->base_commit_id->sha1, SHA1_DIGEST_LENGTH) == 0) { - err = sync_timestamps(ondisk_path, status, ie, &sb); + err = sync_timestamps(worktree->root_fd, path, status, ie, &sb); if (err) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS, @@ -1923,7 +1954,7 @@ update_blob(struct got_worktree *worktree, if (got_fileindex_entry_has_blob(ie) && memcmp(ie->blob_sha1, te->id.sha1, SHA1_DIGEST_LENGTH) == 0) { - err = sync_timestamps(ondisk_path, status, ie, &sb); + err = sync_timestamps(worktree->root_fd, path, status, ie, &sb); goto done; } } @@ -1982,17 +2013,20 @@ update_blob(struct got_worktree *worktree, * Otherwise, a future status walk would treat them as * unmodified files again. */ - err = got_fileindex_entry_update(ie, ondisk_path, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ondisk_path, blob->id.sha1, worktree->base_commit_id->sha1, update_timestamps); } else if (status == GOT_STATUS_MODE_CHANGE) { - err = got_fileindex_entry_update(ie, ondisk_path, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ondisk_path, blob->id.sha1, worktree->base_commit_id->sha1, 0); } else if (status == GOT_STATUS_DELETE) { err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); if (err) goto done; - err = got_fileindex_entry_update(ie, ondisk_path, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ondisk_path, blob->id.sha1, worktree->base_commit_id->sha1, 0); if (err) goto done; @@ -2015,11 +2049,11 @@ update_blob(struct got_worktree *worktree, goto done; if (ie) { - err = got_fileindex_entry_update(ie, ondisk_path, + err = got_fileindex_entry_update(ie, worktree->root_fd, path, blob->id.sha1, worktree->base_commit_id->sha1, 1); } else { err = create_fileindex_entry(&ie, fileindex, - worktree->base_commit_id, ondisk_path, path, + worktree->base_commit_id, ondisk_path, worktree->root_fd, path, &blob->id); } if (err) @@ -2119,7 +2153,8 @@ delete_blob(struct got_worktree *worktree, struct got_fileindex *fileindex, * Preserve the working file and change the deleted blob's * entry into a schedule-add entry. */ - err = got_fileindex_entry_update(ie, ondisk_path, NULL, NULL, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ondisk_path, NULL, NULL, 0); } else { err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE, ie->path); @@ -2335,11 +2370,11 @@ done: } static const struct got_error * -get_fileindex_path(char **fileindex_path, struct got_worktree *worktree) +get_fileindex_path(char **fileindex_path) { const struct got_error *err = NULL; - if (asprintf(fileindex_path, "%s/%s/%s", worktree->root_path, + if (asprintf(fileindex_path, "%s/%s", GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_FILE_INDEX) == -1) { err = got_error_from_errno("asprintf"); *fileindex_path = NULL; @@ -2354,20 +2389,33 @@ open_fileindex(struct got_fileindex **fileindex, char **fileindex_path, { const struct got_error *err = NULL; FILE *index = NULL; + cap_rights_t rights; *fileindex_path = NULL; *fileindex = got_fileindex_alloc(); if (*fileindex == NULL) return got_error_from_errno("got_fileindex_alloc"); - err = get_fileindex_path(fileindex_path, worktree); + err = get_fileindex_path(fileindex_path); if (err) goto done; - index = fopen(*fileindex_path, "rb"); + int fd = openat(worktree->root_fd, *fileindex_path, O_RDONLY); + if (fd == -1) { + err = got_error_from_errno("openat"); + goto done; + } + + cap_rights_init(&rights, CAP_READ, CAP_FCNTL, CAP_FSTAT); + if (caph_rights_limit(fd, &rights) < 0) { + err = got_error_from_errno("caph_rights_limit"); + goto done; + } + + index = fdopen(fd, "rb"); if (index == NULL) { if (errno != ENOENT) - err = got_error_from_errno2("fopen", *fileindex_path); + err = got_error_from_errno2("fdopen", *fileindex_path); } else { err = got_fileindex_read(*fileindex, index); if (fclose(index) != 0 && err == NULL) @@ -2420,14 +2468,14 @@ bump_base_commit_id(void *arg, struct got_fileindex_entry *ie) } static const struct got_error * -sync_fileindex(struct got_fileindex *fileindex, const char *fileindex_path) +sync_fileindex(struct got_fileindex *fileindex, int wt_fd, const char *fileindex_path) { const struct got_error *err = NULL; char *new_fileindex_path = NULL; FILE *new_index = NULL; struct timespec timeout; - err = got_opentemp_named(&new_fileindex_path, &new_index, + err = got_opentemp_named(wt_fd, &new_fileindex_path, &new_index, fileindex_path); if (err) goto done; @@ -2436,8 +2484,8 @@ sync_fileindex(struct got_fileindex *fileindex, const char *fileindex_path) if (err) goto done; - if (rename(new_fileindex_path, fileindex_path) != 0) { - err = got_error_from_errno3("rename", new_fileindex_path, + if (renameat(wt_fd, new_fileindex_path, wt_fd, fileindex_path) != 0) { + err = got_error_from_errno3("renameat", new_fileindex_path, fileindex_path); unlink(new_fileindex_path); } @@ -2706,7 +2754,7 @@ got_worktree_checkout_files(struct got_worktree *worktree, tpd = SIMPLEQ_NEXT(tpd, entry); } - sync_err = sync_fileindex(fileindex, fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -2927,8 +2975,9 @@ merge_file_cb(void *arg, struct got_blob_object *blob1, if (err) goto done; if (status == GOT_STATUS_DELETE) { + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); err = got_fileindex_entry_update(ie, - ondisk_path, blob2->id.sha1, + -1, ondisk_path, blob2->id.sha1, a->worktree->base_commit_id->sha1, 0); if (err) goto done; @@ -2950,7 +2999,8 @@ merge_file_cb(void *arg, struct got_blob_object *blob1, err = got_fileindex_entry_alloc(&ie, path2); if (err) goto done; - err = got_fileindex_entry_update(ie, ondisk_path, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ondisk_path, NULL, NULL, 1); if (err) { got_fileindex_entry_free(ie); @@ -3062,7 +3112,8 @@ merge_files(struct got_worktree *worktree, struct got_fileindex *fileindex, arg.label_orig = label_orig; arg.commit_id2 = commit_id2; err = got_diff_tree(tree1, tree2, "", "", repo, merge_file_cb, &arg, 1); - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -3759,7 +3810,8 @@ schedule_addition(void *arg, unsigned char status, unsigned char staged_status, err = got_fileindex_entry_alloc(&ie, relpath); if (err) goto done; - err = got_fileindex_entry_update(ie, ondisk_path, NULL, NULL, 1); + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ondisk_path, NULL, NULL, 1); if (err) { got_fileindex_entry_free(ie); goto done; @@ -3810,7 +3862,8 @@ got_worktree_schedule_add(struct got_worktree *worktree, if (err) break; } - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -3981,7 +4034,8 @@ got_worktree_schedule_delete(struct got_worktree *worktree, if (err) break; } - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -4285,7 +4339,8 @@ create_patched_content(char **path_outfile, int reverse_patch, if (err) goto done; - err = got_opentemp_named(&path1, &f1, "got-patched-blob"); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &path1, &f1, "got-patched-blob"); if (err) goto done; @@ -4303,7 +4358,8 @@ create_patched_content(char **path_outfile, int reverse_patch, if (err) goto done; - err = got_opentemp_named(path_outfile, &outfile, "got-patched-content"); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, path_outfile, &outfile, "got-patched-content"); if (err) goto done; @@ -4553,7 +4609,8 @@ revert_file(void *arg, unsigned char status, unsigned char staged_status, goto done; if (status == GOT_STATUS_DELETE || status == GOT_STATUS_MODE_CHANGE) { - err = got_fileindex_entry_update(ie, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ondisk_path, blob->id.sha1, a->worktree->base_commit_id->sha1, 1); if (err) @@ -4617,7 +4674,8 @@ got_worktree_revert(struct got_worktree *worktree, if (err) break; } - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -5277,20 +5335,24 @@ update_fileindex_after_commit(struct got_pathlist_head *commitable_paths, ct->staged_status == GOT_STATUS_MODIFY) { got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); - err = got_fileindex_entry_update(ie, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ct->ondisk_path, ct->staged_blob_id->sha1, new_base_commit_id->sha1, !have_staged_files); - } else - err = got_fileindex_entry_update(ie, + } else { + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ct->ondisk_path, ct->blob_id->sha1, new_base_commit_id->sha1, !have_staged_files); + } } else { err = got_fileindex_entry_alloc(&ie, pe->path); if (err) break; - err = got_fileindex_entry_update(ie, ct->ondisk_path, + printf("GOT_FILEINDEX_ENTRY_UPDATE - BROKEN\n"); + err = got_fileindex_entry_update(ie, -1, ct->ondisk_path, ct->blob_id->sha1, new_base_commit_id->sha1, 1); if (err) { got_fileindex_entry_free(ie); @@ -5442,7 +5504,8 @@ commit_worktree(struct got_object_id **new_commit_id, goto done; } /* Lock the reference here to prevent concurrent modification. */ - err = got_ref_open(&head_ref2, repo, head_ref_name, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&head_ref2, -1, head_ref_name, 1); if (err) goto done; err = got_ref_resolve(&head_commit_id2, repo, head_ref2); @@ -5567,7 +5630,8 @@ got_worktree_commit(struct got_object_id **new_commit_id, if (err) goto done; - err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&head_ref, -1, worktree->head_ref_name, 0); if (err) goto done; @@ -5635,7 +5699,8 @@ got_worktree_commit(struct got_object_id **new_commit_id, err = update_fileindex_after_commit(&commitable_paths, *new_commit_id, fileindex, have_staged_files); - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -5747,7 +5812,8 @@ got_worktree_rebase_prepare(struct got_reference **new_base_branch_ref, if (err) goto done; - err = got_ref_open(&wt_branch, repo, worktree->head_ref_name, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&wt_branch, -1, worktree->head_ref_name, 0); if (err) goto done; @@ -5869,16 +5935,19 @@ got_worktree_rebase_continue(struct got_object_id **commit_id, if (err) goto done; - err = got_ref_open(&branch_ref, repo, branch_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&branch_ref, -1, branch_ref_name, 0); if (err) goto done; - err = got_ref_open(branch, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(branch, -1, got_ref_get_symref_target(branch_ref), 0); if (err) goto done; - err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&commit_ref, -1, commit_ref_name, 0); if (err) goto done; @@ -5886,12 +5955,14 @@ got_worktree_rebase_continue(struct got_object_id **commit_id, if (err) goto done; - err = got_ref_open(new_base_branch, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(new_base_branch, -1, new_base_branch_ref_name, 0); if (err) goto done; - err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(tmp_branch, -1, tmp_branch_name, 0); if (err) goto done; done: @@ -6010,7 +6081,8 @@ store_commit_id(const char *commit_ref_name, struct got_object_id *commit_id, const struct got_error *err; struct got_reference *commit_ref = NULL; - err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&commit_ref, -1, commit_ref_name, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; @@ -6055,7 +6127,7 @@ rebase_merge_files(struct got_pathlist_head *merged_paths, /* Work tree is locked/unlocked during rebase preparation/teardown. */ - err = get_fileindex_path(&fileindex_path, worktree); + err = get_fileindex_path(&fileindex_path); if (err) return err; @@ -6144,7 +6216,7 @@ rebase_commit(struct got_object_id **new_commit_id, /* Work tree is locked/unlocked during rebase preparation/teardown. */ - err = get_fileindex_path(&fileindex_path, worktree); + err = get_fileindex_path(&fileindex_path); if (err) return err; @@ -6183,7 +6255,8 @@ rebase_commit(struct got_object_id **new_commit_id, goto done; } - err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&head_ref, -1, worktree->head_ref_name, 0); if (err) goto done; @@ -6221,7 +6294,8 @@ rebase_commit(struct got_object_id **new_commit_id, err = update_fileindex_after_commit(&commitable_paths, *new_commit_id, fileindex, 0); - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -6252,7 +6326,8 @@ got_worktree_rebase_commit(struct got_object_id **new_commit_id, if (err) return err; - err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&commit_ref, -1, commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(&commit_id, repo, commit_ref); @@ -6289,7 +6364,8 @@ got_worktree_histedit_commit(struct got_object_id **new_commit_id, if (err) return err; - err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&commit_ref, -1, commit_ref_name, 0); if (err) goto done; @@ -6317,7 +6393,8 @@ delete_ref(const char *name, struct got_repository *repo) const struct got_error *err; struct got_reference *ref; - err = got_ref_open(&ref, repo, name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&ref, -1, name, 0); if (err) { if (err->code == GOT_ERR_NOT_REF) return NULL; @@ -6425,7 +6502,8 @@ got_worktree_rebase_abort(struct got_worktree *worktree, if (err) return err; - err = got_ref_open(&resolved, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&resolved, -1, got_ref_get_symref_target(new_base_branch), 0); if (err) goto done; @@ -6456,7 +6534,7 @@ got_worktree_rebase_abort(struct got_worktree *worktree, if (err) goto done; - err = get_fileindex_path(&fileindex_path, worktree); + err = get_fileindex_path(&fileindex_path); if (err) goto done; @@ -6475,7 +6553,8 @@ got_worktree_rebase_abort(struct got_worktree *worktree, err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo, progress_cb, progress_arg, NULL, NULL); sync: - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -6540,7 +6619,8 @@ got_worktree_histedit_prepare(struct got_reference **tmp_branch, if (err) goto done; - err = got_ref_open(&wt_branch, repo, worktree->head_ref_name, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&wt_branch, -1, worktree->head_ref_name, 0); if (err) goto done; @@ -6681,25 +6761,29 @@ got_worktree_histedit_continue(struct got_object_id **commit_id, if (err) goto done; - err = got_ref_open(branch_ref, repo, branch_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(branch_ref, -1, branch_ref_name, 0); if (err) goto done; - err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&commit_ref, -1, commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(commit_id, repo, commit_ref); if (err) goto done; - err = got_ref_open(&base_commit_ref, repo, base_commit_ref_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&base_commit_ref, -1, base_commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(base_commit_id, repo, base_commit_ref); if (err) goto done; - err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(tmp_branch, -1, tmp_branch_name, 0); if (err) goto done; done: @@ -6787,7 +6871,8 @@ got_worktree_histedit_abort(struct got_worktree *worktree, if (err) return err; - err = got_ref_open(&resolved, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&resolved, -1, got_ref_get_symref_target(branch), 0); if (err) goto done; @@ -6809,7 +6894,7 @@ got_worktree_histedit_abort(struct got_worktree *worktree, if (err) goto done; - err = get_fileindex_path(&fileindex_path, worktree); + err = get_fileindex_path(&fileindex_path); if (err) goto done; @@ -6828,7 +6913,8 @@ got_worktree_histedit_abort(struct got_worktree *worktree, err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo, progress_cb, progress_arg, NULL, NULL); sync: - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -6855,7 +6941,8 @@ got_worktree_histedit_complete(struct got_worktree *worktree, if (err) return err; - err = got_ref_open(&resolved, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&resolved, -1, got_ref_get_symref_target(edited_branch), 0); if (err) goto done; @@ -6941,11 +7028,13 @@ got_worktree_integrate_prepare(struct got_fileindex **fileindex, if (err) goto done; - err = got_ref_open(branch_ref, repo, refname, 1); + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(branch_ref, -1, refname, 1); if (err) goto done; - err = got_ref_open(base_branch_ref, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(base_branch_ref, -1, got_worktree_get_head_ref_name(worktree), 1); done: if (err) { @@ -6977,7 +7066,7 @@ got_worktree_integrate_continue(struct got_worktree *worktree, char *fileindex_path = NULL; struct got_object_id *tree_id = NULL, *commit_id = NULL; - err = get_fileindex_path(&fileindex_path, worktree); + err = get_fileindex_path(&fileindex_path); if (err) goto done; @@ -7005,7 +7094,8 @@ got_worktree_integrate_continue(struct got_worktree *worktree, err = got_ref_write(base_branch_ref, repo); sync: - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; @@ -7299,7 +7389,8 @@ got_worktree_stage(struct got_worktree *worktree, if (err) return err; - err = got_ref_open(&head_ref, repo, + printf("GOT_REF_OPEN - BROKEN\n"); + err = got_ref_open(&head_ref, -1, got_worktree_get_head_ref_name(worktree), 0); if (err) goto done; @@ -7347,7 +7438,8 @@ got_worktree_stage(struct got_worktree *worktree, goto done; } - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -7402,7 +7494,8 @@ create_unstaged_content(char **path_unstaged_content, if (err) goto done; - err = got_opentemp_named(&path1, &f1, "got-unstage-blob-base"); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &path1, &f1, "got-unstage-blob-base"); if (err) goto done; @@ -7414,7 +7507,8 @@ create_unstaged_content(char **path_unstaged_content, if (err) goto done; - err = got_opentemp_named(&path2, &f2, "got-unstage-blob-staged"); + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, &path2, &f2, "got-unstage-blob-staged"); if (err) goto done; @@ -7437,11 +7531,13 @@ create_unstaged_content(char **path_unstaged_content, if (err) goto done; - err = got_opentemp_named(path_unstaged_content, &outfile, + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, path_unstaged_content, &outfile, "got-unstaged-content"); if (err) goto done; - err = got_opentemp_named(path_new_staged_content, &rejectfile, + printf("GOT_OPENTEMP_NAMED - BROKEN\n"); + err = got_opentemp_named(-1, path_new_staged_content, &rejectfile, "got-new-staged-content"); if (err) goto done; @@ -7786,7 +7882,8 @@ got_worktree_unstage(struct got_worktree *worktree, goto done; } - sync_err = sync_fileindex(fileindex, fileindex_path); + printf("SYNC_FILEINDEX - UNTESTED: %s\n", fileindex_path); + sync_err = sync_fileindex(fileindex, worktree->root_fd, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: @@ -7855,7 +7952,6 @@ got_worktree_path_info(struct got_worktree *worktree, struct got_pathlist_head *paths, got_worktree_path_info_cb info_cb, void *info_arg, got_cancel_cb cancel_cb, void *cancel_arg) - { const struct got_error *err = NULL, *unlockerr; struct got_fileindex *fileindex = NULL; diff --git a/libexec/Makefile.inc b/libexec/Makefile.inc index 7f1fdae6..95f6138f 100644 --- a/libexec/Makefile.inc +++ b/libexec/Makefile.inc @@ -1,5 +1,5 @@ .include "../Makefile.inc" -BINDIR = ${PREFIX}/libexec +BINDIR = ${PREFIX}/usr/libexec MAN = diff --git a/libexec/got-read-blob/Makefile b/libexec/got-read-blob/Makefile index a29d2d33..59b37329 100644 --- a/libexec/got-read-blob/Makefile +++ b/libexec/got-read-blob/Makefile @@ -6,7 +6,7 @@ PROG= got-read-blob SRCS= got-read-blob.c error.c inflate.c object_parse.c \ path.c privsep.c sha1.c -CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib +CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib -static LDFLAGS += -L${.OBJDIR}/../../openbsd-compat LIBADD = util z diff --git a/libexec/got-read-commit/Makefile b/libexec/got-read-commit/Makefile index 27f0d0e4..08773c0a 100644 --- a/libexec/got-read-commit/Makefile +++ b/libexec/got-read-commit/Makefile @@ -6,7 +6,7 @@ PROG= got-read-commit SRCS= got-read-commit.c error.c inflate.c object_parse.c \ path.c privsep.c sha1.c -CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib +CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib -static LDFLAGS += -L${.OBJDIR}/../../openbsd-compat LIBADD = util z diff --git a/libexec/got-read-gitconfig/Makefile b/libexec/got-read-gitconfig/Makefile index 61f5038e..241d3565 100644 --- a/libexec/got-read-gitconfig/Makefile +++ b/libexec/got-read-gitconfig/Makefile @@ -6,7 +6,7 @@ PROG= got-read-gitconfig SRCS= got-read-gitconfig.c error.c inflate.c object_parse.c \ path.c privsep.c sha1.c gitconfig.c -CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib +CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib -static LDFLAGS += -L${.OBJDIR}/../../openbsd-compat LIBADD = util z diff --git a/libexec/got-read-object/Makefile b/libexec/got-read-object/Makefile index f773c60d..07d3687c 100644 --- a/libexec/got-read-object/Makefile +++ b/libexec/got-read-object/Makefile @@ -6,7 +6,7 @@ PROG= got-read-object SRCS= got-read-object.c error.c inflate.c object_parse.c \ path.c privsep.c sha1.c -CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib +CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib -static LDFLAGS += -L${.OBJDIR}/../../openbsd-compat LIBADD = util z diff --git a/libexec/got-read-pack/Makefile b/libexec/got-read-pack/Makefile index 207688dc..0ab657fb 100644 --- a/libexec/got-read-pack/Makefile +++ b/libexec/got-read-pack/Makefile @@ -7,7 +7,7 @@ SRCS= got-read-pack.c delta.c error.c inflate.c object_cache.c \ object_idset.c object_parse.c opentemp.c pack.c path.c \ privsep.c sha1.c delta_cache.c -CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib +CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib -static LDFLAGS += -L${.OBJDIR}/../../openbsd-compat LIBADD = util z diff --git a/libexec/got-read-tree/Makefile b/libexec/got-read-tree/Makefile index d02879a4..0d2d7533 100644 --- a/libexec/got-read-tree/Makefile +++ b/libexec/got-read-tree/Makefile @@ -6,7 +6,7 @@ PROG= got-read-tree SRCS= got-read-tree.c error.c inflate.c object_parse.c \ path.c privsep.c sha1.c -CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib +CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib -static LDFLAGS += -L${.OBJDIR}/../../openbsd-compat LIBADD = util z