Commit 6d5a9006ab2a400b488b9e93ec9647fb9b2a0930

Yang Zhong 2020-12-16T11:16:27

add fd field to got_repository, modify got_packidx_open to use fds These changes are intended to make got more compatible with FreeBSD's Capsicum. ok stsp

diff --git a/include/got_repository.h b/include/got_repository.h
index 9e816e2..58d890d 100644
--- a/include/got_repository.h
+++ b/include/got_repository.h
@@ -32,6 +32,9 @@ const char *got_repo_get_path(struct got_repository *);
  */
 const char *got_repo_get_path_git_dir(struct got_repository *);
 
+/* Obtain the file descriptor of the repository's .git directory. */
+int got_repo_get_fd(struct got_repository *);
+
 /* Obtain the commit author name if parsed from gitconfig, else NULL. */
 const char *got_repo_get_gitconfig_author_name(struct got_repository *);
 
diff --git a/lib/got_lib_pack.h b/lib/got_lib_pack.h
index c56e16c..39aa433 100644
--- a/lib/got_lib_pack.h
+++ b/lib/got_lib_pack.h
@@ -168,7 +168,7 @@ struct got_packfile_obj_data {
 
 const struct got_error *got_packidx_init_hdr(struct got_packidx *, int);
 const struct got_error *got_packidx_open(struct got_packidx **,
-    const char *, int);
+    int, const char *, int);
 const struct got_error *got_packidx_close(struct got_packidx *);
 int got_packidx_get_object_idx(struct got_packidx *, struct got_object_id *);
 const struct got_error *got_packidx_match_id_str_prefix(
diff --git a/lib/got_lib_repository.h b/lib/got_lib_repository.h
index d2a6b78..18d2953 100644
--- a/lib/got_lib_repository.h
+++ b/lib/got_lib_repository.h
@@ -34,6 +34,7 @@
 struct got_repository {
 	char *path;
 	char *path_git_dir;
+	int gitdir_fd;
 
 	/* The pack index cache speeds up search for packed objects. */
 	struct got_packidx *packidx_cache[GOT_PACKIDX_CACHE_SIZE];
diff --git a/lib/pack.c b/lib/pack.c
index 71b5e07..b46583a 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -328,7 +328,8 @@ done:
 }
 
 const struct got_error *
-got_packidx_open(struct got_packidx **packidx, const char *path, int verify)
+got_packidx_open(struct got_packidx **packidx,
+    int dir_fd, const char *relpath, int verify)
 {
 	const struct got_error *err = NULL;
 	struct got_packidx *p;
@@ -340,15 +341,15 @@ got_packidx_open(struct got_packidx **packidx, const char *path, int verify)
 	if (p == NULL)
 		return got_error_from_errno("calloc");
 
-	p->fd = open(path, O_RDONLY | O_NOFOLLOW);
+	p->fd = openat(dir_fd, relpath, O_RDONLY | O_NOFOLLOW);
 	if (p->fd == -1) {
-		err = got_error_from_errno2("open", path);
+		err = got_error_from_errno2("openat", relpath);
 		free(p);
 		return err;
 	}
 
 	if (fstat(p->fd, &sb) != 0) {
-		err = got_error_from_errno2("fstat", path);
+		err = got_error_from_errno2("fstat", relpath);
 		close(p->fd);
 		free(p);
 		return err;
@@ -361,7 +362,7 @@ got_packidx_open(struct got_packidx **packidx, const char *path, int verify)
 		return err;
 	}
 
-	p->path_packidx = strdup(path);
+	p->path_packidx = strdup(relpath);
 	if (p->path_packidx == NULL) {
 		err = got_error_from_errno("strdup");
 		goto done;
diff --git a/lib/repository.c b/lib/repository.c
index 4c8c8ac..7a2d299 100644
--- a/lib/repository.c
+++ b/lib/repository.c
@@ -77,6 +77,12 @@ got_repo_get_path_git_dir(struct got_repository *repo)
 	return repo->path_git_dir;
 }
 
+int
+got_repo_get_fd(struct got_repository *repo)
+{
+	return repo->gitdir_fd;
+}
+
 const char *
 got_repo_get_gitconfig_author_name(struct got_repository *repo)
 {
@@ -333,6 +339,8 @@ open_repo(struct got_repository *repo, const char *path)
 {
 	const struct got_error *err = NULL;
 
+	repo->gitdir_fd = -1;
+
 	/* bare git repository? */
 	repo->path_git_dir = strdup(path);
 	if (repo->path_git_dir == NULL)
@@ -343,6 +351,12 @@ open_repo(struct got_repository *repo, const char *path)
 			err = got_error_from_errno("strdup");
 			goto done;
 		}
+		repo->gitdir_fd = open(repo->path_git_dir, O_DIRECTORY);
+		if (repo->gitdir_fd == -1) {
+			err = got_error_from_errno2("open",
+			    repo->path_git_dir);
+			goto done;
+		}
 		return NULL;
 	}
 
@@ -359,6 +373,12 @@ open_repo(struct got_repository *repo, const char *path)
 			err = got_error_from_errno("strdup");
 			goto done;
 		}
+		repo->gitdir_fd = open(repo->path_git_dir, O_DIRECTORY);
+		if (repo->gitdir_fd == -1) {
+			err = got_error_from_errno2("open",
+			    repo->path_git_dir);
+			goto done;
+		}
 		return NULL;
 	}
 
@@ -369,6 +389,10 @@ done:
 		repo->path = NULL;
 		free(repo->path_git_dir);
 		repo->path_git_dir = NULL;
+		if (repo->gitdir_fd != -1)
+			close(repo->gitdir_fd);
+		repo->gitdir_fd = -1;
+
 	}
 	return err;
 }
@@ -916,11 +940,11 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx,
     struct got_repository *repo, struct got_object_id *id)
 {
 	const struct got_error *err;
-	char *path_packdir;
-	DIR *packdir;
+	DIR *packdir = NULL;
 	struct dirent *dent;
 	char *path_packidx;
 	size_t i;
+	int packdir_fd;
 
 	/* Search pack index cache. */
 	for (i = 0; i < nitems(repo->packidx_cache); i++) {
@@ -944,16 +968,21 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx,
 	}
 	/* No luck. Search the filesystem. */
 
-	path_packdir = got_repo_get_path_objects_pack(repo);
-	if (path_packdir == NULL)
-		return got_error_from_errno("got_repo_get_path_objects_pack");
-
-	packdir = opendir(path_packdir);
-	if (packdir == NULL) {
+	packdir_fd = openat(got_repo_get_fd(repo),
+	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY);
+	if (packdir_fd == -1) {
 		if (errno == ENOENT)
 			err = got_error_no_obj(id);
 		else
-			err = got_error_from_errno2("opendir", path_packdir);
+			err = got_error_from_errno_fmt("openat: %s/%s",
+			    got_repo_get_path_git_dir(repo),
+			    GOT_OBJECTS_PACK_DIR);
+		goto done;
+	}
+
+	packdir = fdopendir(packdir_fd);
+	if (packdir == NULL) {
+		err = got_error_from_errno("fdopendir");
 		goto done;
 	}
 
@@ -963,7 +992,7 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx,
 		if (!is_packidx_filename(dent->d_name, dent->d_namlen))
 			continue;
 
-		if (asprintf(&path_packidx, "%s/%s", path_packdir,
+		if (asprintf(&path_packidx, "%s/%s", GOT_OBJECTS_PACK_DIR,
 		    dent->d_name) == -1) {
 			err = got_error_from_errno("asprintf");
 			goto done;
@@ -983,7 +1012,8 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx,
 			continue; /* already searched */
 		}
 
-		err = got_packidx_open(packidx, path_packidx, 0);
+		err = got_packidx_open(packidx, got_repo_get_fd(repo),
+		    path_packidx, 0);
 		if (err) {
 			free(path_packidx);
 			goto done;
@@ -1003,7 +1033,6 @@ got_repo_search_packidx(struct got_packidx **packidx, int *idx,
 
 	err = got_error_no_obj(id);
 done:
-	free(path_packdir);
 	if (packdir && closedir(packdir) != 0 && err == NULL)
 		err = got_error_from_errno("closedir");
 	return err;
@@ -1032,13 +1061,15 @@ read_packfile_hdr(int fd, struct got_packidx *packidx)
 }
 
 static const struct got_error *
-open_packfile(int *fd, const char *path_packfile, struct got_packidx *packidx)
+open_packfile(int *fd, struct got_repository *repo,
+    const char *relpath, struct got_packidx *packidx)
 {
 	const struct got_error *err = NULL;
 
-	*fd = open(path_packfile, O_RDONLY | O_NOFOLLOW);
+	*fd = openat(got_repo_get_fd(repo), relpath, O_RDONLY | O_NOFOLLOW);
 	if (*fd == -1)
-		return got_error_from_errno2("open", path_packfile);
+		return got_error_from_errno_fmt("openat: %s/%s",
+		    got_repo_get_path_git_dir(repo), relpath);
 
 	if (packidx) {
 		err = read_packfile_hdr(*fd, packidx);
@@ -1088,7 +1119,7 @@ got_repo_cache_pack(struct got_pack **packp, struct got_repository *repo,
 		goto done;
 	}
 
-	err = open_packfile(&pack->fd, path_packfile, packidx);
+	err = open_packfile(&pack->fd, repo, path_packfile, packidx);
 	if (err)
 		goto done;
 
@@ -1200,22 +1231,25 @@ match_packed_object(struct got_object_id **unique_id,
     struct got_repository *repo, const char *id_str_prefix, int obj_type)
 {
 	const struct got_error *err = NULL;
-	char *path_packdir;
-	DIR *packdir;
+	DIR *packdir = NULL;
 	struct dirent *dent;
 	char *path_packidx;
 	struct got_object_id_queue matched_ids;
+	int packdir_fd;
 
 	SIMPLEQ_INIT(&matched_ids);
 
-	path_packdir = got_repo_get_path_objects_pack(repo);
-	if (path_packdir == NULL)
-		return got_error_from_errno("got_repo_get_path_objects_pack");
+	packdir_fd = openat(got_repo_get_fd(repo),
+	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY);
+	if (packdir_fd == -1) {
+		if (errno != ENOENT)
+			err = got_error_from_errno2("openat", GOT_OBJECTS_PACK_DIR);
+		goto done;
+	}
 
-	packdir = opendir(path_packdir);
+	packdir = fdopendir(packdir_fd);
 	if (packdir == NULL) {
-		if (errno != ENOENT)
-			err = got_error_from_errno2("opendir", path_packdir);
+		err = got_error_from_errno("fdopendir");
 		goto done;
 	}
 
@@ -1223,17 +1257,17 @@ match_packed_object(struct got_object_id **unique_id,
 		struct got_packidx *packidx;
 		struct got_object_qid *qid;
 
-
 		if (!is_packidx_filename(dent->d_name, dent->d_namlen))
 			continue;
 
-		if (asprintf(&path_packidx, "%s/%s", path_packdir,
+		if (asprintf(&path_packidx, "%s/%s", GOT_OBJECTS_PACK_DIR,
 		    dent->d_name) == -1) {
-			err = got_error_from_errno("asprintf");
+			err = got_error_from_errno("strdup");
 			break;
 		}
 
-		err = got_packidx_open(&packidx, path_packidx, 0);
+		err = got_packidx_open(&packidx, got_repo_get_fd(repo),
+		    path_packidx, 0);
 		free(path_packidx);
 		if (err)
 			break;
@@ -1274,7 +1308,6 @@ match_packed_object(struct got_object_id **unique_id,
 	}
 done:
 	got_object_id_queue_free(&matched_ids);
-	free(path_packdir);
 	if (packdir && closedir(packdir) != 0 && err == NULL)
 		err = got_error_from_errno("closedir");
 	if (err) {