Commit 5345b4c7e102ec42f81e1b9b229294a0774d9b40

Stefan Sperling 2021-07-06T07:39:36

allow lockfiles to be used in cases where we have a dir_fd and a relative path

diff --git a/lib/got_lib_lockfile.h b/lib/got_lib_lockfile.h
index 379232f..977f28b 100644
--- a/lib/got_lib_lockfile.h
+++ b/lib/got_lib_lockfile.h
@@ -27,5 +27,6 @@ struct got_lockfile {
 	int fd;
 };
 
-const struct got_error *got_lockfile_lock(struct got_lockfile **, const char *);
-const struct got_error *got_lockfile_unlock(struct got_lockfile *);
+const struct got_error *got_lockfile_lock(struct got_lockfile **,
+    const char *, int);
+const struct got_error *got_lockfile_unlock(struct got_lockfile *, int);
diff --git a/lib/lockfile.c b/lib/lockfile.c
index 71a5d73..846038c 100644
--- a/lib/lockfile.c
+++ b/lib/lockfile.c
@@ -31,7 +31,7 @@
 #include "got_lib_lockfile.h"
 
 const struct got_error *
-got_lockfile_lock(struct got_lockfile **lf, const char *path)
+got_lockfile_lock(struct got_lockfile **lf, const char *path, int dir_fd)
 {
 	const struct got_error *err = NULL;
 	int attempts = 5;
@@ -53,9 +53,15 @@ got_lockfile_lock(struct got_lockfile **lf, const char *path)
 	}
 
 	do {
-		(*lf)->fd = open((*lf)->path,
-		    O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK,
-		    GOT_DEFAULT_FILE_MODE);
+		if (dir_fd != -1) {
+			(*lf)->fd = openat(dir_fd, (*lf)->path,
+			    O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK,
+			    GOT_DEFAULT_FILE_MODE);
+		} else {
+			(*lf)->fd = open((*lf)->path,
+			    O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK,
+			    GOT_DEFAULT_FILE_MODE);
+		}
 		if ((*lf)->fd != -1)
 			break;
 		if (errno != EEXIST) {
@@ -69,18 +75,22 @@ got_lockfile_lock(struct got_lockfile **lf, const char *path)
 		err = got_error(GOT_ERR_LOCKFILE_TIMEOUT);
 done:
 	if (err) {
-		got_lockfile_unlock(*lf);
+		got_lockfile_unlock(*lf, dir_fd);
 		*lf = NULL;
 	}
 	return err;
 }
 
 const struct got_error *
-got_lockfile_unlock(struct got_lockfile *lf)
+got_lockfile_unlock(struct got_lockfile *lf, int dir_fd)
 {
 	const struct got_error *err = NULL;
 
-	if (lf->path && lf->fd != -1 && unlink(lf->path) != 0)
+	if (dir_fd != -1) {
+		if (lf->path && lf->fd != -1 &&
+		    unlinkat(dir_fd, lf->path, 0) != 0)
+			err = got_error_from_errno("unlinkat");
+	} else if (lf->path && lf->fd != -1 && unlink(lf->path) != 0)
 		err = got_error_from_errno("unlink");
 	if (lf->fd != -1 && close(lf->fd) == -1 && err == NULL)
 		err = got_error_from_errno("close");
diff --git a/lib/object_create.c b/lib/object_create.c
index 38484be..70dc0d9 100644
--- a/lib/object_create.c
+++ b/lib/object_create.c
@@ -87,7 +87,7 @@ create_object_file(struct got_object_id *id, FILE *content,
 	if (err)
 		goto done;
 
-	err = got_lockfile_lock(&lf, objpath);
+	err = got_lockfile_lock(&lf, objpath, -1);
 	if (err)
 		goto done;
 
@@ -107,7 +107,7 @@ done:
 	if (tmpfile && fclose(tmpfile) == EOF && err == NULL)
 		err = got_error_from_errno("fclose");
 	if (lf)
-		unlock_err = got_lockfile_unlock(lf);
+		unlock_err = got_lockfile_unlock(lf, -1);
 	return err ? err : unlock_err;
 }
 
diff --git a/lib/reference.c b/lib/reference.c
index b89875e..ee703d1 100644
--- a/lib/reference.c
+++ b/lib/reference.c
@@ -174,7 +174,7 @@ parse_ref_file(struct got_reference **ref, const char *name,
 	struct got_lockfile *lf = NULL;
 
 	if (lock) {
-		err = got_lockfile_lock(&lf, abspath);
+		err = got_lockfile_lock(&lf, abspath, -1);
 		if (err) {
 			if (err->code == GOT_ERR_ERRNO && errno == ENOENT)
 				err = got_error_not_ref(name);
@@ -189,7 +189,7 @@ parse_ref_file(struct got_reference **ref, const char *name,
 		else
 			err = got_error_not_ref(name);
 		if (lock)
-			got_lockfile_unlock(lf);
+			got_lockfile_unlock(lf, -1);
 		return err;
 	}
 
@@ -206,7 +206,7 @@ parse_ref_file(struct got_reference **ref, const char *name,
 				err = got_error_from_errno2("getline", abspath);
 		}
 		if (lock)
-			got_lockfile_unlock(lf);
+			got_lockfile_unlock(lf, -1);
 		goto done;
 	}
 	while (linelen > 0 && line[linelen - 1] == '\n') {
@@ -217,12 +217,12 @@ parse_ref_file(struct got_reference **ref, const char *name,
 	err = parse_ref_line(ref, absname, line);
 	if (lock) {
 		if (err)
-			got_lockfile_unlock(lf);
+			got_lockfile_unlock(lf, -1);
 		else {
 			if (*ref)
 				(*ref)->lf = lf;
 			else
-				got_lockfile_unlock(lf);
+				got_lockfile_unlock(lf, -1);
 		}
 	}
 done:
@@ -479,7 +479,7 @@ got_ref_open(struct got_reference **ref, struct got_repository *repo,
 		}
 
 		if (lock) {
-			err = got_lockfile_lock(&lf, packed_refs_path);
+			err = got_lockfile_lock(&lf, packed_refs_path, -1);
 			if (err)
 				goto done;
 		}
@@ -502,7 +502,7 @@ done:
 	if (!err && *ref == NULL)
 		err = got_error_not_ref(refname);
 	if (err && lf)
-		got_lockfile_unlock(lf);
+		got_lockfile_unlock(lf, -1);
 	free(path_refs);
 	return err;
 }
@@ -1175,7 +1175,7 @@ got_ref_write(struct got_reference *ref, struct got_repository *repo)
 	}
 
 	if (ref->lf == NULL) {
-		err = got_lockfile_lock(&lf, path);
+		err = got_lockfile_lock(&lf, path, -1);
 		if (err)
 			goto done;
 	}
@@ -1203,7 +1203,7 @@ got_ref_write(struct got_reference *ref, struct got_repository *repo)
 	tmppath = NULL;
 done:
 	if (ref->lf == NULL && lf)
-		unlock_err = got_lockfile_unlock(lf);
+		unlock_err = got_lockfile_unlock(lf, -1);
 	if (f) {
 		if (fclose(f) == EOF && err == NULL)
 			err = got_error_from_errno("fclose");
@@ -1244,7 +1244,7 @@ delete_packed_ref(struct got_reference *delref, struct got_repository *repo)
 		goto done;
 
 	if (delref->lf == NULL) {
-		err = got_lockfile_lock(&lf, packed_refs_path);
+		err = got_lockfile_lock(&lf, packed_refs_path, -1);
 		if (err)
 			goto done;
 	}
@@ -1348,7 +1348,7 @@ delete_packed_ref(struct got_reference *delref, struct got_repository *repo)
 	}
 done:
 	if (delref->lf == NULL && lf)
-		unlock_err = got_lockfile_unlock(lf);
+		unlock_err = got_lockfile_unlock(lf, -1);
 	if (f) {
 		if (fclose(f) == EOF && err == NULL)
 			err = got_error_from_errno("fclose");
@@ -1385,7 +1385,7 @@ delete_loose_ref(struct got_reference *ref, struct got_repository *repo)
 	}
 
 	if (ref->lf == NULL) {
-		err = got_lockfile_lock(&lf, path);
+		err = got_lockfile_lock(&lf, path, -1);
 		if (err)
 			goto done;
 	}
@@ -1396,7 +1396,7 @@ delete_loose_ref(struct got_reference *ref, struct got_repository *repo)
 		err = got_error_from_errno2("unlink", path);
 done:
 	if (ref->lf == NULL && lf)
-		unlock_err = got_lockfile_unlock(lf);
+		unlock_err = got_lockfile_unlock(lf, -1);
 
 	free(path_refs);
 	free(path);
@@ -1446,7 +1446,7 @@ const struct got_error *
 got_ref_unlock(struct got_reference *ref)
 {
 	const struct got_error *err;
-	err = got_lockfile_unlock(ref->lf);
+	err = got_lockfile_unlock(ref->lf, -1);
 	ref->lf = NULL;
 	return err;
 }
diff --git a/lib/repository_admin.c b/lib/repository_admin.c
index 391b44a..c5017d5 100644
--- a/lib/repository_admin.c
+++ b/lib/repository_admin.c
@@ -1053,7 +1053,7 @@ purge_loose_object(struct got_object_id *id, void *data, void *arg)
 	}
 
 	if (!a->dry_run) {
-		err = got_lockfile_lock(&lf, path);
+		err = got_lockfile_lock(&lf, path, -1);
 		if (err)
 			goto done;
 		if (unlink(path) == -1) {
@@ -1073,7 +1073,7 @@ done:
 		err = got_error_from_errno("close");
 	free(path);
 	if (lf)
-		unlock_err = got_lockfile_unlock(lf);
+		unlock_err = got_lockfile_unlock(lf, -1);
 	return err ? err : unlock_err;
 }