commit - ae8965b97df6dc795f14d7b60a326843a5bfbea0
commit + 7f91a1339fbcdc302e1cd799d2c31ac7acc52bb7
blob - 0680a583c3947e6fb9275ef5c6b35d865f622f0f
blob + 1ad99accb93f9a3c95a0f6063a7d96d028027d63
--- lib/fileindex.c
+++ lib/fileindex.c
strlen(path) + 1 + de->d_namlen);
free(de_path);
if (cmp == 0) {
- err = cb->diff_old_new(cb_arg, *ie, de, path);
+ err = cb->diff_old_new(cb_arg, *ie, de, path,
+ dirfd);
if (err)
break;
*ie = walk_fileindex(fileindex, *ie);
break;
*ie = walk_fileindex(fileindex, *ie);
} else {
- err = cb->diff_new(cb_arg, de, path);
+ err = cb->diff_new(cb_arg, de, path, dirfd);
if (err)
break;
err = walk_dir(&dle, fileindex, ie, dle, dirfd,
*ie = walk_fileindex(fileindex, *ie);
} else if (dle) {
de = dle->data;
- err = cb->diff_new(cb_arg, de, path);
+ err = cb->diff_new(cb_arg, de, path, dirfd);
if (err)
break;
err = walk_dir(&dle, fileindex, ie, dle, dirfd, path,
blob - a0d9a4a7a1b6db01b131c605ab1e4224937d5d8f
blob + 1291a03d512d49e1f0169f4e72fcb7eface50d89
--- lib/got_lib_fileindex.h
+++ lib/got_lib_fileindex.h
struct got_repository *, struct got_fileindex_diff_tree_cb *, void *);
typedef const struct got_error *(*got_fileindex_diff_dir_old_new_cb)(void *,
- struct got_fileindex_entry *, struct dirent *, const char *);
+ struct got_fileindex_entry *, struct dirent *, const char *, int);
typedef const struct got_error *(*got_fileindex_diff_dir_old_cb)(void *,
struct got_fileindex_entry *, const char *);
typedef const struct got_error *(*got_fileindex_diff_dir_new_cb)(void *,
- struct dirent *, const char *);
+ struct dirent *, const char *, int);
struct got_fileindex_diff_dir_cb {
got_fileindex_diff_dir_old_new_cb diff_old_new;
got_fileindex_diff_dir_old_cb diff_old;
blob - 7521cbbef153cce72990ef48d89b7d54d0608873
blob + 7cf8433b8c3d38c3e7fe729474a0d9a5a76f3b69
--- lib/worktree.c
+++ lib/worktree.c
static const struct got_error *
get_file_status(unsigned char *status, struct stat *sb,
struct got_fileindex_entry *ie, const char *abspath,
- struct got_repository *repo)
+ int dirfd, const char *de_name, struct got_repository *repo)
{
const struct got_error *err = NULL;
struct got_object_id id;
*status = GOT_STATUS_NO_CHANGE;
- fd = open(abspath, O_RDONLY | O_NOFOLLOW);
- if (fd == -1 && errno != ENOENT)
- return got_error_from_errno2("open", abspath);
+ /*
+ * Whenever the caller provides a directory descriptor and a
+ * directory entry name for the file, use them! This prevents
+ * race conditions if filesystem paths change beneath our feet.
+ */
+ if (dirfd != -1) {
+ fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW);
+ if (fd == -1 && errno != ENOENT)
+ return got_error_from_errno2("openat", abspath);
+ } else {
+ fd = open(abspath, O_RDONLY | O_NOFOLLOW);
+ if (fd == -1 && errno != ENOENT)
+ return got_error_from_errno2("open", abspath);
+ }
if (fd == -1 || fstat(fd, sb) == -1) {
if (errno == ENOENT) {
if (got_fileindex_entry_has_file_on_disk(ie))
err = got_error_path(ie->path, GOT_ERR_FILE_STAGED);
goto done;
}
- err = get_file_status(&status, &sb, ie, ondisk_path, repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
+ repo);
if (err)
goto done;
if (status == GOT_STATUS_MISSING || status == GOT_STATUS_DELETE)
== -1)
return got_error_from_errno("asprintf");
- err = get_file_status(&status, &sb, ie, ondisk_path, repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo);
if (err)
return err;
path2) == -1)
return got_error_from_errno("asprintf");
- err = get_file_status(&status, &sb, ie, ondisk_path, repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
+ repo);
if (err)
goto done;
path1) == -1)
return got_error_from_errno("asprintf");
- err = get_file_status(&status, &sb, ie, ondisk_path, repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
+ repo);
if (err)
goto done;
strlen(path2));
if (ie) {
err = get_file_status(&status, &sb, ie, ondisk_path,
- repo);
+ -1, NULL, repo);
if (err)
goto done;
if (status != GOT_STATUS_NO_CHANGE &&
return got_error_from_errno("asprintf");
/* Reject merges into a work tree with conflicted files. */
- err = get_file_status(&status, &sb, ie, ondisk_path, a->repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
if (err)
return err;
if (status == GOT_STATUS_CONFLICT)
static const struct got_error *
report_file_status(struct got_fileindex_entry *ie, const char *abspath,
+ int dirfd, const char *de_name,
got_worktree_status_cb status_cb, void *status_arg,
struct got_repository *repo, int report_unchanged)
{
struct got_object_id *blob_idp = NULL, *commit_idp = NULL;
struct got_object_id *staged_blob_idp = NULL;
- err = get_file_status(&status, &sb, ie, abspath, repo);
+ err = get_file_status(&status, &sb, ie, abspath, dirfd, de_name, repo);
if (err)
return err;
static const struct got_error *
status_old_new(void *arg, struct got_fileindex_entry *ie,
- struct dirent *de, const char *parent_path)
+ struct dirent *de, const char *parent_path, int dirfd)
{
const struct got_error *err = NULL;
struct diff_dir_cb_arg *a = arg;
return got_error_from_errno("asprintf");
}
- err = report_file_status(ie, abspath, a->status_cb, a->status_arg,
- a->repo, a->report_unchanged);
+ err = report_file_status(ie, abspath, dirfd, de->d_name,
+ a->status_cb, a->status_arg, a->repo, a->report_unchanged);
free(abspath);
return err;
}
}
static const struct got_error *
-status_new(void *arg, struct dirent *de, const char *parent_path)
+status_new(void *arg, struct dirent *de, const char *parent_path, int dirfd)
{
const struct got_error *err = NULL;
struct diff_dir_cb_arg *a = arg;
ie = got_fileindex_entry_get(fileindex, path, strlen(path));
if (ie)
- return report_file_status(ie, ondisk_path, status_cb,
- status_arg, repo, report_unchanged);
+ return report_file_status(ie, ondisk_path, -1, NULL,
+ status_cb, status_arg, repo, report_unchanged);
if (lstat(ondisk_path, &sb) == -1) {
if (errno != ENOENT)
ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
if (ie) {
- err = get_file_status(&status, &sb, ie, ondisk_path,
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
a->repo);
if (err)
goto done;
relpath) == -1)
return got_error_from_errno("asprintf");
- err = get_file_status(&status, &sb, ie, ondisk_path, a->repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
if (err)
goto done;
return got_error_from_errno("asprintf");
/* Reject rebase of a work tree with modified or staged files. */
- err = get_file_status(&status, &sb, ie, ondisk_path, a->repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo);
free(ondisk_path);
if (err)
return err;
}
}
got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
- err = get_file_status(&status, &sb, ie, ondisk_path, a->repo);
+ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL,
+ a->repo);
if (err)
break;
err = (*a->progress_cb)(a->progress_arg, status, relpath);