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