"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Yang Zhong <yzhong@freebsdfoundation.org>
Subject:
Re: change got_worktree_init, open_worktree to use fds
To:
Yang Zhong <yzhong@freebsdfoundation.org>, gameoftrees@openbsd.org
Date:
Wed, 9 Dec 2020 11:35:08 -0800

Download raw body.

Thread
  • Christian Weisgerber:

    change got_worktree_init, open_worktree to use fds

  • Attached are the changes exactly as you've described. The amount of
    code-changing required does decrease drastically if we move cap_enter()
    after opening the repo and worktree. I suppose the 'secondary benefits'
    of using fds are not relevant in got_worktree_init and _open's case, so
    this is all agreeable to me.
    
    On Wed, Dec 9, 2020 at 10:14 AM Stefan Sperling <stsp@stsp.name> wrote:
    >
    > On Wed, Dec 09, 2020 at 06:28:10PM +0100, Stefan Sperling wrote:
    > > On Wed, Dec 09, 2020 at 09:00:00AM -0800, Yang Zhong wrote:
    > > > Here's the updated diff. With regard to committing, am I OK to
    > > > commit the initial patch (the one that adds the fd field to got_worktree)
    > > > at this point?
    > >
    > > I didn't realize the new patch you posted wasn't self-contained.
    > >
    > > You mean the initial patch quoted below?
    > >
    > > My point of view on this is that you should not actually need most of
    > > these changes if you call cap_enter() after got_worktree_open() and
    > > got_repo_open() are done.
    > > Adding a root_fd to struct got_worktree is fine, of course. I would suggest
    > > to roll a new patch that is self-contained and doesn't assume that your
    > > sandbox is active during got_worktree_init/open() and got_repo_open().
    >
    > To clarify, I imagine this could work somewhat as follows:
    >
    > got_worktree_init() stays as-is (it does not need sandbox protection
    > since all the data involved is created locally.)
    >
    > open_worktree() opens the wt_fd and caches it in struct got_worktree,
    > but otherwise doesn't use it. All the read_meta_file() calls etc. stay
    > as they were (no need for sandbox protection).
    >
    > This should allow capsicum to access worktree->root_fd after
    > got_open_worktree() is done, and configure appropriate rights on the fd.
    >
    > Once the work tree has been opened, and the repository fd and tmpfd have
    > also been opened, the code can enter a capsicum sandbox.
    >
    > It looks to me like this could work.
    > Perhaps I am missing something?
    >
    > I am suggesting this simply in an effort to keep the amount of required
    > changes small. I'd be fine with the original diffs if my suggestions
    > somehow conflict with what capsicum needs.
    diff --git a/lib/fileindex.c b/lib/fileindex.c
    index b46dbb29..6086d328 100644
    --- a/lib/fileindex.c
    +++ b/lib/fileindex.c
    @@ -88,15 +88,15 @@ got_fileindex_perms_to_st(struct got_fileindex_entry *ie)
     
     const struct got_error *
     got_fileindex_entry_update(struct got_fileindex_entry *ie,
    -    const char *ondisk_path, uint8_t *blob_sha1, uint8_t *commit_sha1,
    -    int update_timestamps)
    +    int wt_fd, const char *ondisk_path, uint8_t *blob_sha1,
    +    uint8_t *commit_sha1, int update_timestamps)
     {
     	struct stat sb;
     
    -	if (lstat(ondisk_path, &sb) != 0) {
    +	if (fstatat(wt_fd, ondisk_path, &sb, AT_SYMLINK_NOFOLLOW) != 0) {
     		if (!((ie->flags & GOT_FILEIDX_F_NO_FILE_ON_DISK) &&
     		    errno == ENOENT))
    -			return got_error_from_errno2("lstat", ondisk_path);
    +			return got_error_from_errno2("fstatat", ondisk_path);
     		sb.st_mode = GOT_DEFAULT_FILE_MODE;
     	} else {
     		if (sb.st_mode & S_IFDIR)
    diff --git a/lib/got_lib_fileindex.h b/lib/got_lib_fileindex.h
    index f1005832..537374d7 100644
    --- a/lib/got_lib_fileindex.h
    +++ b/lib/got_lib_fileindex.h
    @@ -108,7 +108,7 @@ uint16_t got_fileindex_perms_from_st(struct stat *);
     mode_t got_fileindex_perms_to_st(struct got_fileindex_entry *);
     
     const struct got_error *got_fileindex_entry_update(struct got_fileindex_entry *,
    -    const char *, uint8_t *, uint8_t *, int);
    +    int, const char *, uint8_t *, uint8_t *, int);
     const struct got_error *got_fileindex_entry_alloc(struct got_fileindex_entry **,
         const char *);
     void got_fileindex_entry_free(struct got_fileindex_entry *);
    diff --git a/lib/got_lib_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/worktree.c b/lib/worktree.c
    index 2e265b00..f4e65ab5 100644
    --- a/lib/worktree.c
    +++ b/lib/worktree.c
    @@ -431,6 +431,12 @@ open_worktree(struct got_worktree **worktree, const char *path)
     
     	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)
     		got_repo_close(repo);
    @@ -507,6 +513,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;
     }
     
    @@ -1179,7 +1186,7 @@ done:
     static const struct got_error *
     create_fileindex_entry(struct got_fileindex_entry **new_iep,
         struct got_fileindex *fileindex, struct got_object_id *base_commit_id,
    -    const char *ondisk_path, const char *path, struct got_object_id *blob_id)
    +    int wt_fd, const char *path, struct got_object_id *blob_id)
     {
     	const struct got_error *err = NULL;
     	struct got_fileindex_entry *new_ie;
    @@ -1190,7 +1197,7 @@ create_fileindex_entry(struct got_fileindex_entry **new_iep,
     	if (err)
     		return err;
     
    -	err = got_fileindex_entry_update(new_ie, ondisk_path,
    +	err = got_fileindex_entry_update(new_ie, wt_fd, path,
     	    blob_id->sha1, base_commit_id->sha1, 1);
     	if (err)
     		goto done;
    @@ -1865,11 +1872,11 @@ done:
      * we had to run a full content comparison to find out.
      */
     static const struct got_error *
    -sync_timestamps(char *ondisk_path, unsigned char status,
    +sync_timestamps(int wt_fd, const char *path, unsigned char status,
         struct got_fileindex_entry *ie, struct stat *sb)
     {
     	if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb))
    -		return got_fileindex_entry_update(ie, ondisk_path,
    +		return got_fileindex_entry_update(ie, wt_fd, path,
     		    ie->blob_sha1, ie->commit_sha1, 1);
     
     	return NULL;
    @@ -1922,7 +1929,8 @@ update_blob(struct got_worktree *worktree,
     		if (got_fileindex_entry_has_commit(ie) &&
     		    memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
     		    SHA1_DIGEST_LENGTH) == 0) {
    -			err = sync_timestamps(ondisk_path, status, ie, &sb);
    +			err = sync_timestamps(worktree->root_fd,
    +			    path, status, ie, &sb);
     			if (err)
     				goto done;
     			err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
    @@ -1932,7 +1940,8 @@ update_blob(struct got_worktree *worktree,
     		if (got_fileindex_entry_has_blob(ie) &&
     		    memcmp(ie->blob_sha1, te->id.sha1,
     		    SHA1_DIGEST_LENGTH) == 0) {
    -			err = sync_timestamps(ondisk_path, status, ie, &sb);
    +			err = sync_timestamps(worktree->root_fd,
    +			    path, status, ie, &sb);
     			goto done;
     		}
     	}
    @@ -1991,17 +2000,17 @@ update_blob(struct got_worktree *worktree,
     		 * Otherwise, a future status walk would treat them as
     		 * unmodified files again.
     		 */
    -		err = got_fileindex_entry_update(ie, ondisk_path,
    +		err = got_fileindex_entry_update(ie, worktree->root_fd, path,
     		    blob->id.sha1, worktree->base_commit_id->sha1,
     		    update_timestamps);
     	} else if (status == GOT_STATUS_MODE_CHANGE) {
    -		err = got_fileindex_entry_update(ie, ondisk_path,
    +		err = got_fileindex_entry_update(ie, worktree->root_fd, path,
     		    blob->id.sha1, worktree->base_commit_id->sha1, 0);
     	} else if (status == GOT_STATUS_DELETE) {
     		err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
     		if (err)
     			goto done;
    -		err = got_fileindex_entry_update(ie, ondisk_path,
    +		err = got_fileindex_entry_update(ie, worktree->root_fd, path,
     		    blob->id.sha1, worktree->base_commit_id->sha1, 0);
     		if (err)
     			goto done;
    @@ -2024,11 +2033,12 @@ update_blob(struct got_worktree *worktree,
     			goto done;
     
     		if (ie) {
    -			err = got_fileindex_entry_update(ie, ondisk_path,
    -			    blob->id.sha1, worktree->base_commit_id->sha1, 1);
    +			err = got_fileindex_entry_update(ie,
    +			    worktree->root_fd, path, blob->id.sha1,
    +			    worktree->base_commit_id->sha1, 1);
     		} else {
     			err = create_fileindex_entry(&ie, fileindex,
    -			    worktree->base_commit_id, ondisk_path, path,
    +			    worktree->base_commit_id, worktree->root_fd, path,
     			    &blob->id);
     		}
     		if (err)
    @@ -2128,8 +2138,8 @@ delete_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
     		 * Preserve the working file and change the deleted blob's
     		 * entry into a schedule-add entry.
     		 */
    -		err = got_fileindex_entry_update(ie, ondisk_path, NULL, NULL,
    -		    0);
    +		err = got_fileindex_entry_update(ie, worktree->root_fd,
    +		    ie->path, NULL, NULL, 0);
     	} else {
     		err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE, ie->path);
     		if (err)
    @@ -2937,7 +2947,7 @@ merge_file_cb(void *arg, struct got_blob_object *blob1,
     				goto done;
     			if (status == GOT_STATUS_DELETE) {
     				err = got_fileindex_entry_update(ie,
    -				    ondisk_path, blob2->id.sha1,
    +				    a->worktree->root_fd, path2, blob2->id.sha1,
     				    a->worktree->base_commit_id->sha1, 0);
     				if (err)
     					goto done;
    @@ -2959,8 +2969,8 @@ merge_file_cb(void *arg, struct got_blob_object *blob1,
     			err = got_fileindex_entry_alloc(&ie, path2);
     			if (err)
     				goto done;
    -			err = got_fileindex_entry_update(ie, ondisk_path,
    -			    NULL, NULL, 1);
    +			err = got_fileindex_entry_update(ie,
    +			    a->worktree->root_fd, path2, NULL, NULL, 1);
     			if (err) {
     				got_fileindex_entry_free(ie);
     				goto done;
    @@ -3779,7 +3789,8 @@ schedule_addition(void *arg, unsigned char status, unsigned char staged_status,
     	err = got_fileindex_entry_alloc(&ie, relpath);
     	if (err)
     		goto done;
    -	err = got_fileindex_entry_update(ie, ondisk_path, NULL, NULL, 1);
    +	err = got_fileindex_entry_update(ie, a->worktree->root_fd,
    +	    relpath, NULL, NULL, 1);
     	if (err) {
     		got_fileindex_entry_free(ie);
     		goto done;
    @@ -4586,7 +4597,8 @@ revert_file(void *arg, unsigned char status, unsigned char staged_status,
     			if (status == GOT_STATUS_DELETE ||
     			    status == GOT_STATUS_MODE_CHANGE) {
     				err = got_fileindex_entry_update(ie,
    -				    ondisk_path, blob->id.sha1,
    +				    a->worktree->root_fd, relpath,
    +				    blob->id.sha1,
     				    a->worktree->base_commit_id->sha1, 1);
     				if (err)
     					goto done;
    @@ -5289,18 +5301,26 @@ done:
     }
     
     static const struct got_error *
    -update_fileindex_after_commit(struct got_pathlist_head *commitable_paths,
    -    struct got_object_id *new_base_commit_id, struct got_fileindex *fileindex,
    -    int have_staged_files)
    +update_fileindex_after_commit(struct got_worktree *worktree,
    +    struct got_pathlist_head *commitable_paths,
    +    struct got_object_id *new_base_commit_id,
    +    struct got_fileindex *fileindex, int have_staged_files)
     {
     	const struct got_error *err = NULL;
     	struct got_pathlist_entry *pe;
    +	char *relpath = NULL;
     
     	TAILQ_FOREACH(pe, commitable_paths, entry) {
     		struct got_fileindex_entry *ie;
     		struct got_commitable *ct = pe->data;
     
     		ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len);
    +
    +		err = got_path_skip_common_ancestor(&relpath,
    +		    worktree->root_path, ct->ondisk_path);
    +		if (err)
    +			goto done;
    +
     		if (ie) {
     			if (ct->status == GOT_STATUS_DELETE ||
     			    ct->staged_status == GOT_STATUS_DELETE) {
    @@ -5310,32 +5330,41 @@ update_fileindex_after_commit(struct got_pathlist_head *commitable_paths,
     				got_fileindex_entry_stage_set(ie,
     				    GOT_FILEIDX_STAGE_NONE);
     				got_fileindex_entry_staged_filetype_set(ie, 0);
    +
     				err = got_fileindex_entry_update(ie,
    -				    ct->ondisk_path, ct->staged_blob_id->sha1,
    +				    worktree->root_fd, relpath,
    +				    ct->staged_blob_id->sha1,
     				    new_base_commit_id->sha1,
     				    !have_staged_files);
     			} else
     				err = got_fileindex_entry_update(ie,
    -				    ct->ondisk_path, ct->blob_id->sha1,
    +				    worktree->root_fd, relpath,
    +				    ct->blob_id->sha1,
     				    new_base_commit_id->sha1,
     				    !have_staged_files);
     		} else {
     			err = got_fileindex_entry_alloc(&ie, pe->path);
     			if (err)
    -				break;
    -			err = got_fileindex_entry_update(ie, ct->ondisk_path,
    -			    ct->blob_id->sha1, new_base_commit_id->sha1, 1);
    +				goto done;
    +			err = got_fileindex_entry_update(ie,
    +			    worktree->root_fd, relpath, ct->blob_id->sha1,
    +			    new_base_commit_id->sha1, 1);
     			if (err) {
     				got_fileindex_entry_free(ie);
    -				break;
    +				goto done;
     			}
     			err = got_fileindex_entry_add(fileindex, ie);
     			if (err) {
     				got_fileindex_entry_free(ie);
    -				break;
    +				goto done;
     			}
     		}
    +		free(relpath);
    +		relpath = NULL;
     	}
    +done:
    +	if (relpath)
    +		free(relpath);
     	return err;
     }
     
    @@ -5666,8 +5695,8 @@ got_worktree_commit(struct got_object_id **new_commit_id,
     	if (err)
     		goto done;
     
    -	err = update_fileindex_after_commit(&commitable_paths, *new_commit_id,
    -	    fileindex, have_staged_files);
    +	err = update_fileindex_after_commit(worktree, &commitable_paths,
    +	    *new_commit_id, fileindex, have_staged_files);
     	sync_err = sync_fileindex(fileindex, fileindex_path);
     	if (sync_err && err == NULL)
     		err = sync_err;
    @@ -6252,8 +6281,8 @@ rebase_commit(struct got_object_id **new_commit_id,
     	if (err)
     		goto done;
     
    -	err = update_fileindex_after_commit(&commitable_paths, *new_commit_id,
    -	    fileindex, 0);
    +	err = update_fileindex_after_commit(worktree, &commitable_paths,
    +	    *new_commit_id, fileindex, 0);
     	sync_err = sync_fileindex(fileindex, fileindex_path);
     	if (sync_err && err == NULL)
     		err = sync_err;
    
  • Christian Weisgerber:

    change got_worktree_init, open_worktree to use fds