Download raw body.
change got_worktree_init, open_worktree to use fds
Here are updated changes. I've attached them this time. diff_1 contains the revised changes from before. > Since you're adding 'int root_fd' to struct got_worktree I don't see a > problem with adding a corresponding argument to got_worktree_open() in > order to initialize the root_fd struct member. diff_2 contains the changes needed for this. It's a lot of the same stuff, so separating it out makes it easier to read. > Careful, the realpath() call in open_worktree() was added to fix a bug. > Is the test which was added in 7d61d89137e4704e685dacfcfb71a42a87ba9f78 > still passing? We're having a bit of trouble getting the tests to work on FreeBSD, but I've installed OpenBSD and have tested the patch there. > > --- 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; > > Why is 'repo_fd' stored here? > Shouldn't the repository's directory fd be part of struct got_repository? You're right; I added this early on and didn't notice until now that I never use it. I've also moved all the variable declarations to the right place. On Tue, Dec 1, 2020 at 3:29 AM Stefan Sperling <stsp@stsp.name> wrote: > > On Mon, Nov 30, 2020 at 09:42:51AM -0800, Yang Zhong wrote: > > Here are some simple changes for initializing and opening worktrees. > > In addition to open() to openat()-style changes, I've also added > > fd fields to the worktree struct, as I'll need it for changes like > > this in other parts of the program. > > Thanks! > > The patch as received on the mailing list cannot be applied. > Looks like your mailer wrapped some overlong lines: > > Patching file got/got.c using Plan A... > Hunk #1 failed at 2711. > patch: **** malformed patch at line 54: path_prefix, repo); > > After addressing the review comments below, could you send an updated patch? > And if your mailer cannot send inline patches without mangling them, could > you send the patch as an attachment? > > > The helper update_meta_file wasn't changed to use fds here, as it > > requires a function like mkostempsat(). > > Right. millert@ is already looking into that. > > > I've changed the signature of got_worktree_init to take in an fd, as > > it's only called in one place. I understand that changing > > got_worktree_open's signature should be avoided, so currently I have > > got_worktree_open open the fd inside the function instead of taking > > it in. I'm not sure what the best solution is in this case. > > So you'll eventually want to pass an fd into got_worktree_open(), right? > > Since you're adding 'int root_fd' to struct got_worktree I don't see a > problem with adding a corresponding argument to got_worktree_open() in > order to initialize the root_fd struct member. Upstream code can store an > open directory file descriptor in struct got_worktree and close it in > got_worktree_close(), even if this file descriptor is not otherwise used > directly. > > > I've also changed got_worktree_open to no longer call realpath() on > > the worktree_path. Instead, where it is needed I make the path > > absolute beforehand (It's only needed for checkout). This is more > > amenable to Capsicum, and doesn't require much change. > > Careful, the realpath() call in open_worktree() was added to fix a bug. > Is the test which was added in 7d61d89137e4704e685dacfcfb71a42a87ba9f78 > still passing? > > Are all the tests passing, for that matter? :) > It would be good to run regression tests on both FreeBSD and OpenBSD > platforms for such patches. As things stand now, the Got 'main' branch > should compile without any extra dependencies in a stock install of > OpenBSD 6.8. How to compile Got and run tests on OpenBSD is documented > in Got's README file. > > > I think these changes are mostly upstream-friendly. I would appreciate > > if you could evaluate the direction of these changes. > > Please avoid declaring new variables in the middle of a scope. This is > incompatible with OpenBSD style(9) rules, which we try to adhere to. > > More feedback inline below: > > > diff --git a/got/got.c b/got/got.c > > index 0357368c..33c8cfa6 100644 > > --- a/got/got.c > > +++ b/got/got.c > > @@ -2711,6 +2711,20 @@ cmd_checkout(int argc, char *argv[]) > > goto done; > > } > > } > > + int worktree_fd = open(worktree_path, O_DIRECTORY); > > So, for example, 'worktree_fd' should be declared at the beginning of > cmd_checkout(). > > > + if (worktree_fd == -1) { > > + error = got_error_from_errno2("open", worktree_path); > > + goto done; > > + } > > + > > + /* Make worktree path absolute */ > > + char *worktree_path_abs = realpath(worktree_path, NULL); > > This should also be declared at the beginning of the scope. You could name > this variable 'worktree_abspath' for consistency with similar variables > elsewhere in the code base. (There's no right or wrong naming here, it's > just that many variables already use the 'abspath' idiom.) > > > + if (worktree_path_abs == NULL) { > > + error = got_error_from_errno2("realpath", worktree_path_abs); > > + goto done; > > + } > > + free(worktree_path); > > + worktree_path = worktree_path_abs; > > > > error = apply_unveil(got_repo_get_path(repo), 0, worktree_path); > > if (error) > > @@ -2720,7 +2734,7 @@ cmd_checkout(int argc, char *argv[]) > > 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; > > > > diff --git a/include/got_path.h b/include/got_path.h > > index 0219d3d3..04558384 100644 > > --- a/include/got_path.h > > +++ b/include/got_path.h > > @@ -132,3 +132,4 @@ 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_fileat(int, const char *, > > const char *); > > diff --git a/include/got_worktree.h b/include/got_worktree.h > > index 24fddd52..13b13521 100644 > > --- a/include/got_worktree.h > > +++ b/include/got_worktree.h > > @@ -42,12 +42,11 @@ 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 *); > > > > /* > > 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; > > Why is 'repo_fd' stored here? > Shouldn't the repository's directory fd be part of struct got_repository? > > > char *path_prefix; > > struct got_object_id *base_commit_id; > > char *head_ref_name; > > diff --git a/lib/path.c b/lib/path.c > > index a670334c..655304a0 100644 > > --- a/lib/path.c > > +++ b/lib/path.c > > @@ -513,11 +513,17 @@ got_path_find_prog(char **filename, const char *prog) > > > > const struct got_error * > > got_path_create_file(const char *path, const char *content) > > +{ > > + return got_path_create_fileat(AT_FDCWD, path, content); > > +} > > + > > +const struct got_error * > > +got_path_create_fileat(int dir_fd, const char *path, const char *content) > > { > > const struct got_error *err = NULL; > > int fd = -1; > > > > - 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); > > diff --git a/lib/worktree.c b/lib/worktree.c > > index 2e265b00..30ce5dea 100644 > > --- a/lib/worktree.c > > +++ b/lib/worktree.c > > @@ -67,15 +67,15 @@ > > #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_fileat(worktree_fd, path, content); > > free(path); > > return err; > > } > > @@ -120,7 +120,7 @@ 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; > > @@ -136,7 +136,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); > > @@ -204,7 +204,7 @@ write_head_ref(const char *path_got, struct > > got_reference *head_ref) > > } > > > > 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,29 +237,23 @@ 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; > > - } > > Is the above really not needed anymore? As long as the removal of this code > doesn't make any tests fail, removing the code should be fine. > > > - > > /* 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; > > > > @@ -272,18 +266,18 @@ got_worktree_init(const char *path, struct > > got_reference *head_ref, > > 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 +293,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 +302,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,10 +317,9 @@ 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) > > { > > const struct got_error *err = NULL; > > - char *path_got; > > char *formatstr = NULL; > > char *uuidstr = NULL; > > char *path_lock = NULL; > > @@ -338,26 +331,20 @@ open_worktree(struct got_worktree **worktree, > > const char *path) > > > > *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) { > > + if (asprintf(&path_lock, "%s/%s", GOT_WORKTREE_GOT_DIR, > > 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); > > + 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); > > + err = read_meta_file(&formatstr, worktree_fd, > > GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_FORMAT); > > if (err) > > goto done; > > > > @@ -379,27 +366,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, > > GOT_WORKTREE_GOT_DIR, > > 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, > > GOT_WORKTREE_GOT_DIR, > > 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, > > GOT_WORKTREE_GOT_DIR, > > 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, GOT_WORKTREE_GOT_DIR, > > GOT_WORKTREE_UUID); > > if (err) > > goto done; > > uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); > > @@ -417,7 +404,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, > > GOT_WORKTREE_GOT_DIR, > > GOT_WORKTREE_HEAD_REF); > > if (err) > > goto done; > > @@ -431,10 +418,14 @@ open_worktree(struct got_worktree **worktree, > > const char *path) > > > > err = got_gotconfig_read(&(*worktree)->gotconfig, > > (*worktree)->gotconfig_path); > > + > > + int repo_fd = open(got_repo_get_path_git_dir(repo), O_DIRECTORY); > > Another variable declaration which should be moved to the beginning > of this scope. > > Everything else about this patch is looking great, thank you! > > > + > > + (*worktree)->root_fd = worktree_fd; > > + (*worktree)->repo_fd = repo_fd; > > done: > > if (repo) > > got_repo_close(repo); > > - free(path_got); > > free(path_lock); > > free(base_commit_id_str); > > free(uuidstr); > > @@ -456,15 +447,20 @@ got_worktree_open(struct got_worktree > > **worktree, const char *path) > > { > > const struct got_error *err = NULL; > > char *worktree_path; > > + int worktree_fd; > > > > worktree_path = strdup(path); > > if (worktree_path == NULL) > > return got_error_from_errno("strdup"); > > > > + worktree_fd = open(worktree_path, O_DIRECTORY); > > + if (worktree_fd == -1) > > + return got_error_from_errno2("open", worktree_path); > > + > > for (;;) { > > char *parent_path; > > > > - err = open_worktree(worktree, worktree_path); > > + err = open_worktree(worktree, worktree_fd, worktree_path); > > if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { > > free(worktree_path); > > return err; > > @@ -484,7 +480,9 @@ got_worktree_open(struct got_worktree **worktree, > > const char *path) > > break; > > } > > free(worktree_path); > > + close(worktree_fd); > > worktree_path = parent_path; > > + worktree_fd = open(parent_path, O_DIRECTORY); > > } > > > > free(worktree_path); > > @@ -507,6 +505,8 @@ got_worktree_close(struct got_worktree *worktree) > > free(worktree->gotconfig_path); > > got_gotconfig_free(worktree->gotconfig); > > free(worktree); > > + close(worktree->root_fd); > > + close(worktree->repo_fd); > > return err; > > } > > > > diff --git a/got/got.c b/got/got.c index 0357368c..e8cfb93a 100644 --- a/got/got.c +++ b/got/got.c @@ -2602,11 +2602,13 @@ cmd_checkout(int argc, char *argv[]) struct got_worktree *worktree = NULL; char *repo_path = NULL; char *worktree_path = NULL; + char *worktree_abspath = NULL; const char *path_prefix = ""; const char *branch_name = GOT_REF_HEAD; char *commit_id_str = NULL; char *cwd = NULL; int ch, same_path_prefix, allow_nonempty = 0; + int worktree_fd = -1; struct got_pathlist_head paths; struct got_checkout_progress_arg cpa; @@ -2711,6 +2713,20 @@ cmd_checkout(int argc, char *argv[]) goto done; } } + worktree_fd = open(worktree_path, O_DIRECTORY); + if (worktree_fd == -1) { + error = got_error_from_errno2("open", worktree_path); + goto done; + } + + /* Make worktree path absolute */ + worktree_abspath = realpath(worktree_path, NULL); + if (worktree_abspath == NULL) { + error = got_error_from_errno2("realpath", worktree_abspath); + goto done; + } + free(worktree_path); + worktree_path = worktree_abspath; error = apply_unveil(got_repo_get_path(repo), 0, worktree_path); if (error) @@ -2720,7 +2736,7 @@ cmd_checkout(int argc, char *argv[]) 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; diff --git a/include/got_path.h b/include/got_path.h index 0219d3d3..04558384 100644 --- a/include/got_path.h +++ b/include/got_path.h @@ -132,3 +132,4 @@ 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_fileat(int, const char *, const char *); diff --git a/include/got_worktree.h b/include/got_worktree.h index 24fddd52..13b13521 100644 --- a/include/got_worktree.h +++ b/include/got_worktree.h @@ -42,12 +42,11 @@ 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 *); /* diff --git a/lib/got_lib_worktree.h b/lib/got_lib_worktree.h index 067bac22..651bcc8f 100644 --- a/lib/got_lib_worktree.h +++ b/lib/got_lib_worktree.h @@ -17,6 +17,7 @@ struct got_worktree { char *root_path; char *repo_path; + int root_fd; char *path_prefix; struct got_object_id *base_commit_id; char *head_ref_name; diff --git a/lib/path.c b/lib/path.c index a670334c..655304a0 100644 --- a/lib/path.c +++ b/lib/path.c @@ -513,11 +513,17 @@ got_path_find_prog(char **filename, const char *prog) const struct got_error * got_path_create_file(const char *path, const char *content) +{ + return got_path_create_fileat(AT_FDCWD, path, content); +} + +const struct got_error * +got_path_create_fileat(int dir_fd, const char *path, const char *content) { const struct got_error *err = NULL; int fd = -1; - 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); diff --git a/lib/worktree.c b/lib/worktree.c index 2e265b00..8bf4b7ff 100644 --- a/lib/worktree.c +++ b/lib/worktree.c @@ -67,15 +67,15 @@ #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_fileat(worktree_fd, path, content); free(path); return err; } @@ -120,7 +120,7 @@ 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; @@ -136,7 +136,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); @@ -204,7 +204,7 @@ write_head_ref(const char *path_got, struct got_reference *head_ref) } 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,29 +237,23 @@ 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; @@ -272,18 +266,18 @@ got_worktree_init(const char *path, struct got_reference *head_ref, 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 +293,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 +302,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,10 +317,9 @@ 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) { const struct got_error *err = NULL; - char *path_got; char *formatstr = NULL; char *uuidstr = NULL; char *path_lock = NULL; @@ -338,26 +331,20 @@ open_worktree(struct got_worktree **worktree, const char *path) *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) { + if (asprintf(&path_lock, "%s/%s", GOT_WORKTREE_GOT_DIR, 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); + 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); + err = read_meta_file(&formatstr, worktree_fd, GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_FORMAT); if (err) goto done; @@ -379,27 +366,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, GOT_WORKTREE_GOT_DIR, 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, GOT_WORKTREE_GOT_DIR, 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, GOT_WORKTREE_GOT_DIR, 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, GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_UUID); if (err) goto done; uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); @@ -417,7 +404,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, GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_HEAD_REF); if (err) goto done; @@ -431,10 +418,11 @@ open_worktree(struct got_worktree **worktree, const char *path) err = got_gotconfig_read(&(*worktree)->gotconfig, (*worktree)->gotconfig_path); + + (*worktree)->root_fd = worktree_fd; done: if (repo) got_repo_close(repo); - free(path_got); free(path_lock); free(base_commit_id_str); free(uuidstr); @@ -456,15 +444,20 @@ got_worktree_open(struct got_worktree **worktree, const char *path) { const struct got_error *err = NULL; char *worktree_path; + int worktree_fd; worktree_path = strdup(path); if (worktree_path == NULL) return got_error_from_errno("strdup"); + worktree_fd = open(worktree_path, O_DIRECTORY); + if (worktree_fd == -1) + return got_error_from_errno2("open", worktree_path); + for (;;) { char *parent_path; - err = open_worktree(worktree, worktree_path); + err = open_worktree(worktree, worktree_fd, worktree_path); if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { free(worktree_path); return err; @@ -484,7 +477,9 @@ got_worktree_open(struct got_worktree **worktree, const char *path) break; } free(worktree_path); + close(worktree_fd); worktree_path = parent_path; + worktree_fd = open(parent_path, O_DIRECTORY); } free(worktree_path); @@ -507,6 +502,7 @@ got_worktree_close(struct got_worktree *worktree) free(worktree->gotconfig_path); got_gotconfig_free(worktree->gotconfig); free(worktree); + close(worktree->root_fd); return err; } diff --git a/got/got.c b/got/got.c index e8cfb93a..a2cfacec 100644 --- a/got/got.c +++ b/got/got.c @@ -2007,6 +2007,7 @@ cmd_fetch(int argc, char *argv[]) struct got_fetch_progress_arg fpa; int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0; int delete_refs = 0, replace_tags = 0; + int cwd_fd = -1; TAILQ_INIT(&refs); TAILQ_INIT(&symrefs); @@ -2088,9 +2089,14 @@ cmd_fetch(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -2740,7 +2746,7 @@ cmd_checkout(int argc, char *argv[]) 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); if (error != NULL) goto done; @@ -2983,7 +2989,7 @@ cmd_update(int argc, char *argv[]) const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; - char *worktree_path = NULL; + char *cwd = NULL; struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; const char *branch_name = NULL; @@ -2991,6 +2997,7 @@ cmd_update(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch; + int cwd_fd = -1; struct got_update_progress_arg upa; TAILQ_INIT(&paths); @@ -3019,16 +3026,22 @@ cmd_update(int argc, char *argv[]) "unveil", NULL) == -1) err(1, "pledge"); #endif - worktree_path = getcwd(NULL, 0); - if (worktree_path == NULL) { + cwd = getcwd(NULL, 0); + if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, worktree_path); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "update", - worktree_path); + cwd); goto done; } @@ -3130,7 +3143,7 @@ cmd_update(int argc, char *argv[]) printf("Already up-to-date\n"); print_update_progress_stats(&upa); done: - free(worktree_path); + free(cwd); TAILQ_FOREACH(pe, &paths, entry) free((char *)pe->path); got_pathlist_free(&paths); @@ -3711,6 +3724,7 @@ cmd_log(int argc, char *argv[]) int diff_context = -1, ch; int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0; int reverse_display_order = 0; + int cwd_fd = -1; const char *errstr; struct got_reflist_head refs; @@ -3785,9 +3799,13 @@ cmd_log(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; error = NULL; @@ -4124,6 +4142,7 @@ cmd_diff(int argc, char *argv[]) int type1, type2; int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch; int force_text_diff = 0; + int cwd_fd = -1; const char *errstr; char *path = NULL; @@ -4171,11 +4190,16 @@ cmd_diff(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (argc <= 1) { if (repo_path) errx(1, "-r option can't be used when diffing a work tree"); - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "diff", @@ -4206,7 +4230,7 @@ cmd_diff(int argc, char *argv[]) id_str1 = argv[0]; id_str2 = argv[1]; if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) { @@ -4467,6 +4491,7 @@ cmd_blame(int argc, char *argv[]) char *commit_id_str = NULL; struct blame_cb_args bca; int ch, obj_type, i; + int cwd_fd = -1; off_t filesize; memset(&bca, 0, sizeof(bca)); @@ -4508,8 +4533,13 @@ cmd_blame(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -4789,6 +4819,7 @@ cmd_tree(int argc, char *argv[]) struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; int show_ids = 0, recurse = 0; + int cwd_fd = -1; int ch; #ifndef PROFILE @@ -4836,8 +4867,13 @@ cmd_tree(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -4973,6 +5009,7 @@ cmd_status(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, i; + int cwd_fd = -1; TAILQ_INIT(&paths); @@ -5017,8 +5054,13 @@ cmd_status(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "status", cwd); @@ -5182,6 +5224,7 @@ cmd_ref(int argc, char *argv[]) struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; int ch, do_list = 0, do_delete = 0; + int cwd_fd = -1; const char *obj_arg = NULL, *symref_target= NULL; char *refname = NULL; @@ -5267,9 +5310,14 @@ cmd_ref(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -5512,6 +5560,7 @@ cmd_branch(int argc, char *argv[]) struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; int ch, do_list = 0, do_show = 0, do_update = 1; + int cwd_fd = -1; const char *delref = NULL, *commit_id_arg = NULL; struct got_reference *ref = NULL; struct got_pathlist_head paths; @@ -5582,9 +5631,14 @@ cmd_branch(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -6052,6 +6106,7 @@ cmd_tag(int argc, char *argv[]) char *gitconfig_path = NULL; const char *tag_name, *commit_id_arg = NULL, *tagmsg = NULL; int ch, do_list = 0; + int cwd_fd = -1; while ((ch = getopt(argc, argv, "c:m:r:l")) != -1) { switch (ch) { @@ -6109,9 +6164,14 @@ cmd_tag(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } if (repo_path == NULL) { - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else @@ -6214,6 +6274,7 @@ cmd_add(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, no_ignores = 0; + int cwd_fd = -1; TAILQ_INIT(&paths); @@ -6247,8 +6308,13 @@ cmd_add(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "add", cwd); @@ -6352,6 +6418,7 @@ cmd_remove(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i; + int cwd_fd = -1; TAILQ_INIT(&paths); @@ -6403,7 +6470,13 @@ cmd_remove(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "remove", cwd); @@ -6611,6 +6684,7 @@ cmd_revert(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, pflag = 0; + int cwd_fd = -1; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; struct choose_patch_arg cpa; @@ -6652,7 +6726,13 @@ cmd_revert(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "revert", cwd); @@ -6825,6 +6905,7 @@ cmd_commit(int argc, char *argv[]) char *gitconfig_path = NULL, *editor = NULL, *author = NULL; int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0; int allow_bad_symlinks = 0; + int cwd_fd = -1; struct got_pathlist_head paths; TAILQ_INIT(&paths); @@ -6857,7 +6938,13 @@ cmd_commit(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "commit", cwd); @@ -6970,6 +7057,7 @@ cmd_cherrypick(int argc, char *argv[]) struct got_object_qid *pid; struct got_reference *head_ref = NULL; int ch; + int cwd_fd = -1; struct got_update_progress_arg upa; while ((ch = getopt(argc, argv, "")) != -1) { @@ -6996,7 +7084,13 @@ cmd_cherrypick(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "cherrypick", @@ -7093,6 +7187,7 @@ cmd_backout(int argc, char *argv[]) struct got_object_qid *pid; struct got_reference *head_ref = NULL; int ch; + int cwd_fd = -1; struct got_update_progress_arg upa; while ((ch = getopt(argc, argv, "")) != -1) { @@ -7119,7 +7214,13 @@ cmd_backout(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "backout", cwd); @@ -7483,6 +7584,7 @@ cmd_rebase(int argc, char *argv[]) struct got_commit_object *commit = NULL; int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0; int histedit_in_progress = 0; + int cwd_fd = -1; unsigned char rebase_status = GOT_STATUS_NO_CHANGE; struct got_object_id_queue commits; struct got_pathlist_head merged_paths; @@ -7527,7 +7629,13 @@ cmd_rebase(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "rebase", cwd); @@ -8593,6 +8701,7 @@ cmd_histedit(int argc, char *argv[]) struct got_update_progress_arg upa; int edit_in_progress = 0, abort_edit = 0, continue_edit = 0; int edit_logmsg_only = 0; + int cwd_fd = -1; const char *edit_script_path = NULL; unsigned char rebase_status = GOT_STATUS_NO_CHANGE; struct got_object_id_queue commits; @@ -8660,7 +8769,13 @@ cmd_histedit(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "histedit", cwd); @@ -9015,6 +9130,7 @@ cmd_integrate(int argc, char *argv[]) struct got_fileindex *fileindex = NULL; struct got_object_id *commit_id = NULL, *base_commit_id = NULL; int ch; + int cwd_fd = -1; struct got_update_progress_arg upa; while ((ch = getopt(argc, argv, "")) != -1) { @@ -9041,8 +9157,13 @@ cmd_integrate(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "integrate", @@ -9182,6 +9303,7 @@ cmd_stage(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0; + int cwd_fd = -1; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; struct choose_patch_arg cpa; @@ -9226,8 +9348,13 @@ cmd_stage(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "stage", cwd); @@ -9302,6 +9429,7 @@ cmd_unstage(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, pflag = 0; + int cwd_fd = -1; struct got_update_progress_arg upa; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; @@ -9339,8 +9467,13 @@ cmd_unstage(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "unstage", cwd); @@ -9558,6 +9691,7 @@ cmd_cat(int argc, char *argv[]) const char *commit_id_str = NULL; struct got_object_id *id = NULL, *commit_id = NULL; int ch, obj_type, i, force_path = 0; + int cwd_fd = -1; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", @@ -9594,7 +9728,13 @@ cmd_cat(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } - error = got_worktree_open(&worktree, cwd); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } + + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) { @@ -9779,6 +9919,7 @@ cmd_info(int argc, char *argv[]) struct got_pathlist_entry *pe; char *uuidstr = NULL; int ch, show_files = 0; + int cwd_fd = -1; TAILQ_INIT(&paths); @@ -9803,8 +9944,13 @@ cmd_info(int argc, char *argv[]) error = got_error_from_errno("getcwd"); goto done; } + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) { + error = got_error_from_errno2("open", cwd); + goto done; + } - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "status", cwd); diff --git a/include/got_worktree.h b/include/got_worktree.h index 13b13521..0e517bef 100644 --- a/include/got_worktree.h +++ b/include/got_worktree.h @@ -53,7 +53,7 @@ const struct got_error *got_worktree_init(int, const char *, struct got_referenc * 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 *); /* Dispose of an open work tree. */ const struct got_error *got_worktree_close(struct got_worktree *); diff --git a/lib/worktree.c b/lib/worktree.c index 8bf4b7ff..f4670cfb 100644 --- a/lib/worktree.c +++ b/lib/worktree.c @@ -440,20 +440,16 @@ 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) { const struct got_error *err = NULL; char *worktree_path; - int worktree_fd; worktree_path = strdup(path); if (worktree_path == NULL) return got_error_from_errno("strdup"); - worktree_fd = open(worktree_path, O_DIRECTORY); - if (worktree_fd == -1) - return got_error_from_errno2("open", worktree_path); - for (;;) { char *parent_path; diff --git a/tog/tog.c b/tog/tog.c index 1bee4fa4..e47736b0 100644 --- a/tog/tog.c +++ b/tog/tog.c @@ -23,6 +23,7 @@ #define _XOPEN_SOURCE_EXTENDED #include <curses.h> #undef _XOPEN_SOURCE_EXTENDED +#include <fcntl.h> #include <panel.h> #include <locale.h> #include <signal.h> @@ -2707,6 +2708,7 @@ cmd_log(int argc, char *argv[]) char *in_repo_path = NULL, *repo_path = NULL, *cwd = NULL; char *start_commit = NULL, *head_ref_name = NULL; int ch, log_branches = 0; + int cwd_fd = -1; struct tog_view *view; #ifndef PROFILE @@ -2744,8 +2746,11 @@ cmd_log(int argc, char *argv[]) cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) + return got_error_from_errno2("open", cwd); - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; @@ -3800,6 +3805,7 @@ cmd_diff(int argc, char *argv[]) char *label1 = NULL, *label2 = NULL; int diff_context = 3, ignore_whitespace = 0; int ch, force_text_diff = 0; + int cwd_fd = -1; const char *errstr; struct tog_view *view; @@ -3849,8 +3855,11 @@ cmd_diff(int argc, char *argv[]) cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) + return got_error_from_errno2("open", cwd); - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; @@ -4721,6 +4730,7 @@ cmd_blame(int argc, char *argv[]) struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; int ch; + int cwd_fd = -1; struct tog_view *view; #ifndef PROFILE @@ -4755,8 +4765,11 @@ cmd_blame(int argc, char *argv[]) cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) + return got_error_from_errno2("open", cwd); - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; @@ -5541,6 +5554,7 @@ cmd_tree(int argc, char *argv[]) struct got_commit_object *commit = NULL; struct got_tree_object *tree = NULL; int ch; + int cwd_fd = -1; struct tog_view *view; #ifndef PROFILE @@ -5575,8 +5589,11 @@ cmd_tree(int argc, char *argv[]) cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) + return got_error_from_errno2("open", cwd); - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; @@ -6280,6 +6297,7 @@ cmd_ref(int argc, char *argv[]) struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; int ch; + int cwd_fd = -1; struct tog_view *view; #ifndef PROFILE @@ -6311,8 +6329,11 @@ cmd_ref(int argc, char *argv[]) cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) + return got_error_from_errno2("open", cwd); - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; @@ -6428,12 +6449,16 @@ tog_log_with_path(int argc, char *argv[]) struct got_object_id *commit_id = NULL, *id = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *commit_id_str = NULL, **cmd_argv = NULL; + int cwd_fd = -1; cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); + cwd_fd = open(cwd, O_DIRECTORY); + if (cwd_fd == -1) + return got_error_from_errno2("open", cwd); - error = got_worktree_open(&worktree, cwd); + error = got_worktree_open(&worktree, cwd_fd, cwd); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done;
change got_worktree_init, open_worktree to use fds