Download raw body.
make gotadmin run in a work tree
On Sun, Nov 14, 2021 at 11:37:31AM +0100, Stefan Sperling wrote: > On Sun, Nov 14, 2021 at 11:23:59AM +0100, Stefan Sperling wrote: > > gotweb benefits a little as well by shedding some weight, as in > > linking less unused worktree code into the binary. > > Actually, gotweb doesn't need any worktree.c code at all. I have > removed worktree.c from its list of source files on the main branch. Glad you caught this :) > > Here is a rebased patch which ignores the gotweb side of things. > ok! > ----------------------------------------------- > commit 1813a7c09b4ab5f28fa7c139625db5f4362ce61c (gotadmin-worktree) > from: Stefan Sperling <stsp@stsp.name> > date: Sun Nov 14 10:35:31 2021 UTC > > let gotadmin find the repository automatically if invoked in a work tree > > Move a small amount of code from worktree.c to a new file worktree_open.c, > which contains everything required to open and close a work tree and inspect > some of its basic parameters. This can be used by gotadmin. > > diff d34cb66cb9f25f0f06b250b99d9aa3de97c3cb7d 9e8331df1736d9c4835ad8d2419d1fe9c3642215 > blob - 4b9ae8539216e6a771ac12438cc2e7bb79a42ced > blob + 7e44f914b454fcd320fd03610f840109df3f7539 > --- got/Makefile > +++ got/Makefile > @@ -7,7 +7,7 @@ SRCS= got.c blame.c commit_graph.c delta.c diff.c \ > diffreg.c error.c fileindex.c object.c object_cache.c \ > object_idset.c object_parse.c opentemp.c path.c pack.c \ > privsep.c reference.c repository.c sha1.c worktree.c \ > - inflate.c buf.c rcsutil.c diff3.c lockfile.c \ > + worktree_open.c inflate.c buf.c rcsutil.c diff3.c lockfile.c \ > deflate.c object_create.c delta_cache.c fetch.c \ > gotconfig.c diff_main.c diff_atomize_text.c \ > diff_myers.c diff_output.c diff_output_plain.c \ > blob - e40715b4c34c91855cc2dd46670ca0ba712541a6 > blob + 47d9d105cc92076d9e33ac2abdf1adf89ab25dc9 > --- gotadmin/Makefile > +++ gotadmin/Makefile > @@ -8,7 +8,7 @@ SRCS= gotadmin.c \ > inflate.c lockfile.c object.c object_cache.c object_create.c \ > object_idset.c object_parse.c opentemp.c pack.c pack_create.c \ > path.c privsep.c reference.c repository.c repository_admin.c \ > - sha1.c bloom.c murmurhash2.c > + worktree_open.c sha1.c bloom.c murmurhash2.c > MAN = ${PROG}.1 > > CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib > blob - 95a7aa49c8f72ab6c542ca943a37c5fc2cca1932 > blob + f0ef0abde989951cff823fdaf07ad4a0528aca1f > --- gotadmin/gotadmin.1 > +++ gotadmin/gotadmin.1 > @@ -68,6 +68,9 @@ are as follows: > Use the repository at the specified path. > If not specified, assume the repository is located at or above the current > working directory. > +If this directory is a > +.Xr got 1 > +work tree, use the repository path associated with this work tree. > .El > .It Cm pack Oo Fl a Oc Oo Fl r Ar repository-path Oc Oo Fl x Ar reference Oc Op Ar reference ... > Generate a new pack file and a corresponding pack file index. > @@ -101,6 +104,9 @@ Unless this option is specified, only loose objects wi > Use the repository at the specified path. > If not specified, assume the repository is located at or above the current > working directory. > +If this directory is a > +.Xr got 1 > +work tree, use the repository path associated with this work tree. > .It Fl x Ar reference > Exclude objects reachable via the specified > .Ar reference > @@ -274,6 +280,9 @@ remove any files from disk. > Use the repository at the specified path. > If not specified, assume the repository is located at or above the current > working directory. > +If this directory is a > +.Xr got 1 > +work tree, use the repository path associated with this work tree. > .It Fl q > Suppress progress reporting and disk space summary output. > .El > blob - b3c2e764d6748d711145b67ef6017d4d695e00b7 > blob + 4a20c98ded30054a59e95d5cd5fc9f422d019da1 > --- gotadmin/gotadmin.c > +++ gotadmin/gotadmin.c > @@ -42,6 +42,7 @@ > #include "got_path.h" > #include "got_privsep.h" > #include "got_opentemp.h" > +#include "got_worktree.h" > > #ifndef nitems > #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) > @@ -232,10 +233,43 @@ usage_info(void) > } > > static const struct got_error * > +get_repo_path(char **repo_path) > +{ > + const struct got_error *err = NULL; > + struct got_worktree *worktree = NULL; > + char *cwd; > + > + *repo_path = NULL; > + > + cwd = getcwd(NULL, 0); > + if (cwd == NULL) > + return got_error_from_errno("getcwd"); > + > + err = got_worktree_open(&worktree, cwd); > + if (err) { > + if (err->code != GOT_ERR_NOT_WORKTREE) > + goto done; > + err = NULL; > + } > + > + if (worktree) > + *repo_path = strdup(got_worktree_get_repo_path(worktree)); > + else > + *repo_path = strdup(cwd); > + if (*repo_path == NULL) > + err = got_error_from_errno("strdup"); > +done: > + if (worktree) > + got_worktree_close(worktree); > + free(cwd); > + return err; > +} > + > +static const struct got_error * > cmd_info(int argc, char *argv[]) > { > const struct got_error *error = NULL; > - char *cwd = NULL, *repo_path = NULL; > + char *repo_path = NULL; > struct got_repository *repo = NULL; > const struct got_gotconfig *gotconfig = NULL; > int ch, npackfiles, npackedobj, nobj; > @@ -265,13 +299,12 @@ cmd_info(int argc, char *argv[]) > NULL) == -1) > err(1, "pledge"); > #endif > - cwd = getcwd(NULL, 0); > - if (cwd == NULL) { > - error = got_error_from_errno("getcwd"); > - goto done; > + if (repo_path == NULL) { > + error = get_repo_path(&repo_path); > + if (error) > + goto done; > } > - > - error = got_repo_open(&repo, repo_path ? repo_path : cwd, NULL); > + error = got_repo_open(&repo, repo_path, NULL); > if (error) > goto done; > > @@ -333,7 +366,7 @@ cmd_info(int argc, char *argv[]) > done: > if (repo) > got_repo_close(repo); > - free(cwd); > + free(repo_path); > return error; > } > > @@ -521,7 +554,7 @@ static const struct got_error * > cmd_pack(int argc, char *argv[]) > { > const struct got_error *error = NULL; > - char *cwd = NULL, *repo_path = NULL; > + char *repo_path = NULL; > struct got_repository *repo = NULL; > int ch, i, loose_obj_only = 1; > struct got_object_id *pack_hash = NULL; > @@ -571,13 +604,12 @@ cmd_pack(int argc, char *argv[]) > NULL) == -1) > err(1, "pledge"); > #endif > - cwd = getcwd(NULL, 0); > - if (cwd == NULL) { > - error = got_error_from_errno("getcwd"); > - goto done; > + if (repo_path == NULL) { > + error = get_repo_path(&repo_path); > + if (error) > + goto done; > } > - > - error = got_repo_open(&repo, repo_path ? repo_path : cwd, NULL); > + error = got_repo_open(&repo, repo_path, NULL); > if (error) > goto done; > > @@ -651,7 +683,7 @@ done: > got_ref_list_free(&include_refs); > free(id_str); > free(pack_hash); > - free(cwd); > + free(repo_path); > return error; > } > > @@ -1002,7 +1034,7 @@ static const struct got_error * > cmd_cleanup(int argc, char *argv[]) > { > const struct got_error *error = NULL; > - char *cwd = NULL, *repo_path = NULL; > + char *repo_path = NULL; > struct got_repository *repo = NULL; > int ch, dry_run = 0, npacked = 0, verbosity = 0; > int remove_lonely_packidx = 0, ignore_mtime = 0; > @@ -1050,13 +1082,12 @@ cmd_cleanup(int argc, char *argv[]) > NULL) == -1) > err(1, "pledge"); > #endif > - cwd = getcwd(NULL, 0); > - if (cwd == NULL) { > - error = got_error_from_errno("getcwd"); > - goto done; > + if (repo_path == NULL) { > + error = get_repo_path(&repo_path); > + if (error) > + goto done; > } > - > - error = got_repo_open(&repo, repo_path ? repo_path : cwd, NULL); > + error = got_repo_open(&repo, repo_path, NULL); > if (error) > goto done; > > @@ -1121,6 +1152,6 @@ cmd_cleanup(int argc, char *argv[]) > done: > if (repo) > got_repo_close(repo); > - free(cwd); > + free(repo_path); > return error; > } > blob - 8b445649ab78fb4dde26c6c0d79295a825c10599 > blob + 31c6214885278c6568978931a3f60491140afca9 > --- lib/worktree.c > +++ lib/worktree.c > @@ -118,70 +118,6 @@ done: > } > > static const struct got_error * > -read_meta_file(char **content, const char *path_got, const char *name) > -{ > - const struct got_error *err = NULL; > - char *path; > - int fd = -1; > - ssize_t n; > - struct stat sb; > - > - *content = NULL; > - > - if (asprintf(&path, "%s/%s", path_got, name) == -1) { > - err = got_error_from_errno("asprintf"); > - path = NULL; > - goto done; > - } > - > - fd = open(path, O_RDONLY | O_NOFOLLOW); > - if (fd == -1) { > - if (errno == ENOENT) > - err = got_error_path(path, GOT_ERR_WORKTREE_META); > - else > - err = got_error_from_errno2("open", path); > - 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)); > - goto done; > - } > - > - if (fstat(fd, &sb) != 0) { > - err = got_error_from_errno2("fstat", path); > - goto done; > - } > - *content = calloc(1, sb.st_size); > - if (*content == NULL) { > - err = got_error_from_errno("calloc"); > - goto done; > - } > - > - n = read(fd, *content, sb.st_size); > - if (n != sb.st_size) { > - err = (n == -1 ? got_error_from_errno2("read", path) : > - got_error_path(path, GOT_ERR_WORKTREE_META)); > - goto done; > - } > - if ((*content)[sb.st_size - 1] != '\n') { > - err = got_error_path(path, GOT_ERR_WORKTREE_META); > - goto done; > - } > - (*content)[sb.st_size - 1] = '\0'; > - > -done: > - if (fd != -1 && close(fd) == -1 && err == NULL) > - err = got_error_from_errno2("close", path_got); > - free(path); > - if (err) { > - free(*content); > - *content = NULL; > - } > - return err; > -} > - > -static const struct got_error * > write_head_ref(const char *path_got, struct got_reference *head_ref) > { > const struct got_error *err = NULL; > @@ -320,226 +256,7 @@ done: > return err; > } > > -static const struct got_error * > -open_worktree(struct got_worktree **worktree, const char *path) > -{ > - const struct got_error *err = NULL; > - char *path_got; > - char *formatstr = NULL; > - char *uuidstr = NULL; > - char *path_lock = NULL; > - char *base_commit_id_str = NULL; > - int version, fd = -1; > - const char *errstr; > - struct got_repository *repo = NULL; > - uint32_t uuid_status; > - > - *worktree = NULL; > - > - if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) { > - err = got_error_from_errno("asprintf"); > - path_got = NULL; > - goto done; > - } > - > - if (asprintf(&path_lock, "%s/%s", path_got, GOT_WORKTREE_LOCK) == -1) { > - err = got_error_from_errno("asprintf"); > - path_lock = NULL; > - goto done; > - } > - > - fd = open(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); > - if (err) > - goto done; > - > - version = strtonum(formatstr, 1, INT_MAX, &errstr); > - if (errstr) { > - err = got_error_msg(GOT_ERR_WORKTREE_META, > - "could not parse work tree format version number"); > - goto done; > - } > - if (version != GOT_WORKTREE_FORMAT_VERSION) { > - err = got_error(GOT_ERR_WORKTREE_VERS); > - goto done; > - } > - > - *worktree = calloc(1, sizeof(**worktree)); > - if (*worktree == NULL) { > - err = got_error_from_errno("calloc"); > - goto done; > - } > - (*worktree)->lockfd = -1; > - > - (*worktree)->root_path = realpath(path, NULL); > - if ((*worktree)->root_path == NULL) { > - err = got_error_from_errno2("realpath", path); > - goto done; > - } > - err = read_meta_file(&(*worktree)->repo_path, path_got, > - GOT_WORKTREE_REPOSITORY); > - if (err) > - goto done; > - > - err = read_meta_file(&(*worktree)->path_prefix, path_got, > - GOT_WORKTREE_PATH_PREFIX); > - if (err) > - goto done; > - > - err = read_meta_file(&base_commit_id_str, path_got, > - GOT_WORKTREE_BASE_COMMIT); > - if (err) > - goto done; > - > - err = read_meta_file(&uuidstr, path_got, GOT_WORKTREE_UUID); > - if (err) > - goto done; > - uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); > - if (uuid_status != uuid_s_ok) { > - err = got_error_uuid(uuid_status, "uuid_from_string"); > - goto done; > - } > - > - err = got_repo_open(&repo, (*worktree)->repo_path, NULL); > - if (err) > - goto done; > - > - err = got_object_resolve_id_str(&(*worktree)->base_commit_id, repo, > - base_commit_id_str); > - if (err) > - goto done; > - > - err = read_meta_file(&(*worktree)->head_ref_name, path_got, > - GOT_WORKTREE_HEAD_REF); > - if (err) > - goto done; > - > - if (asprintf(&(*worktree)->gotconfig_path, "%s/%s/%s", > - (*worktree)->root_path, > - GOT_WORKTREE_GOT_DIR, GOT_GOTCONFIG_FILENAME) == -1) { > - err = got_error_from_errno("asprintf"); > - goto done; > - } > - > - err = got_gotconfig_read(&(*worktree)->gotconfig, > - (*worktree)->gotconfig_path); > - > - (*worktree)->root_fd = open((*worktree)->root_path, O_DIRECTORY); > - if ((*worktree)->root_fd == -1) { > - err = got_error_from_errno2("open", (*worktree)->root_path); > - goto done; > - } > -done: > - if (repo) { > - const struct got_error *close_err = got_repo_close(repo); > - if (err == NULL) > - err = close_err; > - } > - free(path_got); > - free(path_lock); > - free(base_commit_id_str); > - free(uuidstr); > - free(formatstr); > - if (err) { > - if (fd != -1) > - close(fd); > - if (*worktree != NULL) > - got_worktree_close(*worktree); > - *worktree = NULL; > - } else > - (*worktree)->lockfd = fd; > - > - return err; > -} > - > const struct got_error * > -got_worktree_open(struct got_worktree **worktree, const char *path) > -{ > - const struct got_error *err = NULL; > - char *worktree_path; > - > - worktree_path = strdup(path); > - if (worktree_path == NULL) > - return got_error_from_errno("strdup"); > - > - for (;;) { > - char *parent_path; > - > - err = open_worktree(worktree, worktree_path); > - if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { > - free(worktree_path); > - return err; > - } > - if (*worktree) { > - free(worktree_path); > - return NULL; > - } > - if (worktree_path[0] == '/' && worktree_path[1] == '\0') > - break; > - err = got_path_dirname(&parent_path, worktree_path); > - if (err) { > - if (err->code != GOT_ERR_BAD_PATH) { > - free(worktree_path); > - return err; > - } > - break; > - } > - free(worktree_path); > - worktree_path = parent_path; > - } > - > - free(worktree_path); > - return got_error(GOT_ERR_NOT_WORKTREE); > -} > - > -const struct got_error * > -got_worktree_close(struct got_worktree *worktree) > -{ > - const struct got_error *err = NULL; > - > - if (worktree->lockfd != -1) { > - if (close(worktree->lockfd) == -1) > - err = got_error_from_errno2("close", > - got_worktree_get_root_path(worktree)); > - } > - if (close(worktree->root_fd) == -1 && err == NULL) > - err = got_error_from_errno2("close", > - got_worktree_get_root_path(worktree)); > - free(worktree->repo_path); > - free(worktree->path_prefix); > - free(worktree->base_commit_id); > - free(worktree->head_ref_name); > - free(worktree->root_path); > - free(worktree->gotconfig_path); > - got_gotconfig_free(worktree->gotconfig); > - free(worktree); > - return err; > -} > - > -const char * > -got_worktree_get_root_path(struct got_worktree *worktree) > -{ > - return worktree->root_path; > -} > - > -const char * > -got_worktree_get_repo_path(struct got_worktree *worktree) > -{ > - return worktree->repo_path; > -} > -const char * > -got_worktree_get_path_prefix(struct got_worktree *worktree) > -{ > - return worktree->path_prefix; > -} > - > -const struct got_error * > got_worktree_match_path_prefix(int *match, struct got_worktree *worktree, > const char *path_prefix) > { > blob - /dev/null > blob + 4a589cf5ece62d780a9e4fac1215b2df6a5ea5cc (mode 644) > --- /dev/null > +++ lib/worktree_open.c > @@ -0,0 +1,324 @@ > +/* > + * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/stat.h> > +#include <sys/queue.h> > + > +#include <errno.h> > +#include <fcntl.h> > +#include <limits.h> > +#include <stddef.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <uuid.h> > + > +#include "got_cancel.h" > +#include "got_error.h" > +#include "got_reference.h" > +#include "got_path.h" > +#include "got_worktree.h" > +#include "got_repository.h" > +#include "got_gotconfig.h" > +#include "got_object.h" > + > +#include "got_lib_worktree.h" > +#include "got_lib_gotconfig.h" > + > +static const struct got_error * > +read_meta_file(char **content, const char *path_got, const char *name) > +{ > + const struct got_error *err = NULL; > + char *path; > + int fd = -1; > + ssize_t n; > + struct stat sb; > + > + *content = NULL; > + > + if (asprintf(&path, "%s/%s", path_got, name) == -1) { > + err = got_error_from_errno("asprintf"); > + path = NULL; > + goto done; > + } > + > + fd = open(path, O_RDONLY | O_NOFOLLOW); > + if (fd == -1) { > + if (errno == ENOENT) > + err = got_error_path(path, GOT_ERR_WORKTREE_META); > + else > + err = got_error_from_errno2("open", path); > + 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)); > + goto done; > + } > + > + if (fstat(fd, &sb) != 0) { > + err = got_error_from_errno2("fstat", path); > + goto done; > + } > + *content = calloc(1, sb.st_size); > + if (*content == NULL) { > + err = got_error_from_errno("calloc"); > + goto done; > + } > + > + n = read(fd, *content, sb.st_size); > + if (n != sb.st_size) { > + err = (n == -1 ? got_error_from_errno2("read", path) : > + got_error_path(path, GOT_ERR_WORKTREE_META)); > + goto done; > + } > + if ((*content)[sb.st_size - 1] != '\n') { > + err = got_error_path(path, GOT_ERR_WORKTREE_META); > + goto done; > + } > + (*content)[sb.st_size - 1] = '\0'; > + > +done: > + if (fd != -1 && close(fd) == -1 && err == NULL) > + err = got_error_from_errno2("close", path_got); > + free(path); > + if (err) { > + free(*content); > + *content = NULL; > + } > + return err; > +} > + > +static const struct got_error * > +open_worktree(struct got_worktree **worktree, const char *path) > +{ > + const struct got_error *err = NULL; > + char *path_got; > + char *formatstr = NULL; > + char *uuidstr = NULL; > + char *path_lock = NULL; > + char *base_commit_id_str = NULL; > + int version, fd = -1; > + const char *errstr; > + struct got_repository *repo = NULL; > + uint32_t uuid_status; > + > + *worktree = NULL; > + > + if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) { > + err = got_error_from_errno("asprintf"); > + path_got = NULL; > + goto done; > + } > + > + if (asprintf(&path_lock, "%s/%s", path_got, GOT_WORKTREE_LOCK) == -1) { > + err = got_error_from_errno("asprintf"); > + path_lock = NULL; > + goto done; > + } > + > + fd = open(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); > + if (err) > + goto done; > + > + version = strtonum(formatstr, 1, INT_MAX, &errstr); > + if (errstr) { > + err = got_error_msg(GOT_ERR_WORKTREE_META, > + "could not parse work tree format version number"); > + goto done; > + } > + if (version != GOT_WORKTREE_FORMAT_VERSION) { > + err = got_error(GOT_ERR_WORKTREE_VERS); > + goto done; > + } > + > + *worktree = calloc(1, sizeof(**worktree)); > + if (*worktree == NULL) { > + err = got_error_from_errno("calloc"); > + goto done; > + } > + (*worktree)->lockfd = -1; > + > + (*worktree)->root_path = realpath(path, NULL); > + if ((*worktree)->root_path == NULL) { > + err = got_error_from_errno2("realpath", path); > + goto done; > + } > + err = read_meta_file(&(*worktree)->repo_path, path_got, > + GOT_WORKTREE_REPOSITORY); > + if (err) > + goto done; > + > + err = read_meta_file(&(*worktree)->path_prefix, path_got, > + GOT_WORKTREE_PATH_PREFIX); > + if (err) > + goto done; > + > + err = read_meta_file(&base_commit_id_str, path_got, > + GOT_WORKTREE_BASE_COMMIT); > + if (err) > + goto done; > + > + err = read_meta_file(&uuidstr, path_got, GOT_WORKTREE_UUID); > + if (err) > + goto done; > + uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); > + if (uuid_status != uuid_s_ok) { > + err = got_error_uuid(uuid_status, "uuid_from_string"); > + goto done; > + } > + > + err = got_repo_open(&repo, (*worktree)->repo_path, NULL); > + if (err) > + goto done; > + > + err = got_object_resolve_id_str(&(*worktree)->base_commit_id, repo, > + base_commit_id_str); > + if (err) > + goto done; > + > + err = read_meta_file(&(*worktree)->head_ref_name, path_got, > + GOT_WORKTREE_HEAD_REF); > + if (err) > + goto done; > + > + if (asprintf(&(*worktree)->gotconfig_path, "%s/%s/%s", > + (*worktree)->root_path, > + GOT_WORKTREE_GOT_DIR, GOT_GOTCONFIG_FILENAME) == -1) { > + err = got_error_from_errno("asprintf"); > + goto done; > + } > + > + err = got_gotconfig_read(&(*worktree)->gotconfig, > + (*worktree)->gotconfig_path); > + > + (*worktree)->root_fd = open((*worktree)->root_path, O_DIRECTORY); > + if ((*worktree)->root_fd == -1) { > + err = got_error_from_errno2("open", (*worktree)->root_path); > + goto done; > + } > +done: > + if (repo) { > + const struct got_error *close_err = got_repo_close(repo); > + if (err == NULL) > + err = close_err; > + } > + free(path_got); > + free(path_lock); > + free(base_commit_id_str); > + free(uuidstr); > + free(formatstr); > + if (err) { > + if (fd != -1) > + close(fd); > + if (*worktree != NULL) > + got_worktree_close(*worktree); > + *worktree = NULL; > + } else > + (*worktree)->lockfd = fd; > + > + return err; > +} > + > +const struct got_error * > +got_worktree_open(struct got_worktree **worktree, const char *path) > +{ > + const struct got_error *err = NULL; > + char *worktree_path; > + > + worktree_path = strdup(path); > + if (worktree_path == NULL) > + return got_error_from_errno("strdup"); > + > + for (;;) { > + char *parent_path; > + > + err = open_worktree(worktree, worktree_path); > + if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { > + free(worktree_path); > + return err; > + } > + if (*worktree) { > + free(worktree_path); > + return NULL; > + } > + if (worktree_path[0] == '/' && worktree_path[1] == '\0') > + break; > + err = got_path_dirname(&parent_path, worktree_path); > + if (err) { > + if (err->code != GOT_ERR_BAD_PATH) { > + free(worktree_path); > + return err; > + } > + break; > + } > + free(worktree_path); > + worktree_path = parent_path; > + } > + > + free(worktree_path); > + return got_error(GOT_ERR_NOT_WORKTREE); > +} > + > +const struct got_error * > +got_worktree_close(struct got_worktree *worktree) > +{ > + const struct got_error *err = NULL; > + > + if (worktree->lockfd != -1) { > + if (close(worktree->lockfd) == -1) > + err = got_error_from_errno2("close", > + got_worktree_get_root_path(worktree)); > + } > + if (close(worktree->root_fd) == -1 && err == NULL) > + err = got_error_from_errno2("close", > + got_worktree_get_root_path(worktree)); > + free(worktree->repo_path); > + free(worktree->path_prefix); > + free(worktree->base_commit_id); > + free(worktree->head_ref_name); > + free(worktree->root_path); > + free(worktree->gotconfig_path); > + got_gotconfig_free(worktree->gotconfig); > + free(worktree); > + return err; > +} > + > +const char * > +got_worktree_get_root_path(struct got_worktree *worktree) > +{ > + return worktree->root_path; > +} > + > +const char * > +got_worktree_get_repo_path(struct got_worktree *worktree) > +{ > + return worktree->repo_path; > +} > + > +const char * > +got_worktree_get_path_prefix(struct got_worktree *worktree) > +{ > + return worktree->path_prefix; > +} > blob - f7072d7a4b02817f653b795674c32ae7feabcc0b > blob + ba79d5e787ada9939dea4f62aae062cea501f845 > --- tog/Makefile > +++ tog/Makefile > @@ -7,7 +7,7 @@ SRCS= tog.c blame.c commit_graph.c delta.c diff.c \ > diffreg.c error.c fileindex.c object.c object_cache.c \ > object_idset.c object_parse.c opentemp.c path.c pack.c \ > privsep.c reference.c repository.c sha1.c worktree.c \ > - utf8.c inflate.c buf.c rcsutil.c diff3.c \ > + worktree_open.c utf8.c inflate.c buf.c rcsutil.c diff3.c \ > lockfile.c deflate.c object_create.c delta_cache.c \ > gotconfig.c diff_main.c diff_atomize_text.c \ > diff_myers.c diff_output.c diff_output_plain.c \ -- Tracey Emery
make gotadmin run in a work tree