commit - 03df25b334950c4fa76dc9a86b3df050861298ce
commit + 2f17228ee55ecd8c69a9d0dac94841c7894d0d6d
blob - 5d5cf0446f8b605dd7cd8ba1001a12d2aa7e0a83
blob + bc14b937b2e2688bef36d04f7659e90265482817
--- got/got.c
+++ got/got.c
struct got_commit_graph *graph = NULL;
err = got_ref_open(&head_ref, repo,
- got_worktree_get_head_ref_name(worktree));
+ got_worktree_get_head_ref_name(worktree), 0);
if (err)
return err;
if (error)
goto done;
- error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (error != NULL)
goto done;
if (commit_id_str == NULL) {
struct got_reference *head_ref;
- error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (error != NULL)
goto done;
error = got_ref_resolve(&commit_id, repo, head_ref);
if (start_commit == NULL) {
struct got_reference *head_ref;
- error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (error != NULL)
return error;
error = got_ref_resolve(&id, repo, head_ref);
error = got_object_open_as_commit(&commit, repo, id);
} else {
struct got_reference *ref;
- error = got_ref_open(&ref, repo, start_commit);
+ error = got_ref_open(&ref, repo, start_commit, 0);
if (error == NULL) {
int obj_type;
error = got_ref_resolve(&id, repo, ref);
if (commit_id_str == NULL) {
struct got_reference *head_ref;
- error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (error != NULL)
goto done;
error = got_ref_resolve(&commit_id, repo, head_ref);
if (commit_id_str == NULL) {
struct got_reference *head_ref;
- error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (error != NULL)
goto done;
error = got_ref_resolve(&commit_id, repo, head_ref);
const struct got_error *err = NULL;
struct got_reference *ref;
- err = got_ref_open(&ref, repo, refname);
+ err = got_ref_open(&ref, repo, refname, 0);
if (err)
return err;
blob - 5c3eed9a3a8b0f5dbc490b7a2cfeccd2fd6f744e
blob + 019df06a6d16642bb74799bcec1df6d150cd3e99
--- include/got_reference.h
+++ include/got_reference.h
/*
* Attempt to open the reference with the provided name in a repository.
- * The caller must dispose of it with got_ref_close().
+ * The caller must dispose of the reference with got_ref_close().
+ * Optionally, the underlying reference file can be locked before it is opened
+ * to prevent concurrent modification of the reference, in which case the file
+ * must be unlocked with got_ref_unlock() before got_ref_close() is called.
*/
const struct got_error *got_ref_open(struct got_reference **,
- struct got_repository *, const char *);
+ struct got_repository *, const char *, int);
/*
* Allocate a new reference for a given object ID.
/* Delete a reference from its on-disk path in the repository. */
const struct got_error *got_ref_delete(struct got_reference *,
struct got_repository *);
+
+/* Unlock a reference which was opened in locked state. */
+const struct got_error *got_ref_unlock(struct got_reference *);
blob - d1b38a65bfd2d837c561df0239d29aab9207b914
blob + 953af3c70ff0826f5cf8d91f4bdeac05b7ad5293
--- lib/reference.c
+++ lib/reference.c
struct got_ref ref;
struct got_symref symref;
} ref;
+
+ struct got_lockfile *lf;
};
static const struct got_error *
static const struct got_error *
parse_ref_file(struct got_reference **ref, const char *name,
- const char *abspath)
+ const char *abspath, int lock)
{
const struct got_error *err = NULL;
FILE *f;
char *line;
size_t len;
const char delim[3] = {'\0', '\0', '\0'};
+ struct got_lockfile *lf = NULL;
+ if (lock) {
+ err = got_lockfile_lock(&lf, abspath);
+ if (err)
+ return (err);
+ }
+
f = fopen(abspath, "rb");
if (f == NULL)
return NULL;
}
err = parse_ref_line(ref, name, line);
+ if (err == NULL && lf)
+ (*ref)->lf = lf;
done:
free(line);
- if (fclose(f) != 0 && err == NULL)
+ if (fclose(f) != 0 && err == NULL) {
err = got_error_prefix_errno("fclose");
+ if (lf)
+ got_lockfile_unlock(lf);
+ if (*ref) {
+ got_ref_close(*ref);
+ *ref = NULL;
+ }
+ }
return err;
}
static const struct got_error *
open_ref(struct got_reference **ref, const char *path_refs, const char *subdir,
- const char *name)
+ const char *name, int lock)
{
const struct got_error *err = NULL;
char *path = NULL;
goto done;
}
- err = parse_ref_file(ref, absname, normpath);
+ err = parse_ref_file(ref, absname, normpath, lock);
done:
if (!ref_is_absolute && !ref_is_well_known)
free(absname);
const struct got_error *
got_ref_open(struct got_reference **ref, struct got_repository *repo,
- const char *refname)
+ const char *refname, int lock)
{
const struct got_error *err = NULL;
char *path_refs = NULL;
/* Search on-disk refs before packed refs! */
for (i = 0; i < nitems(subdirs); i++) {
- err = open_ref(ref, path_refs, subdirs[i], refname);
+ err = open_ref(ref, path_refs, subdirs[i], refname,
+ lock);
if (err || *ref)
goto done;
}
goto done;
}
+ if (lock) {
+ err = got_lockfile_lock(&(*ref)->lf, packed_refs_path);
+ if (err)
+ goto done;
+ }
f = fopen(packed_refs_path, "rb");
free(packed_refs_path);
if (f != NULL) {
}
}
- err = open_ref(ref, path_refs, "", refname);
+ err = open_ref(ref, path_refs, "", refname, lock);
if (err)
goto done;
done:
struct got_reference *nextref;
const struct got_error *err;
- err = got_ref_open(&nextref, repo, ref->ref.symref.ref);
+ err = got_ref_open(&nextref, repo, ref->ref.symref.ref, 0);
if (err)
return err;
switch (dent->d_type) {
case DT_REG:
- err = open_ref(&ref, path_refs, subdir, dent->d_name);
+ err = open_ref(&ref, path_refs, subdir, dent->d_name,
+ 0);
if (err)
goto done;
if (ref) {
err = got_error_prefix_errno("get_refs_dir_path");
goto done;
}
- err = open_ref(&ref, path_refs, "", GOT_REF_HEAD);
+ err = open_ref(&ref, path_refs, "", GOT_REF_HEAD, 0);
if (err)
goto done;
err = insert_ref(&new, refs, ref, repo);
}
}
- err = got_lockfile_lock(&lf, path);
- if (err)
- goto done;
+ if (ref->lf == NULL) {
+ err = got_lockfile_lock(&lf, path);
+ if (err)
+ goto done;
+ }
/* XXX: check if old content matches our expectations? */
goto done;
}
done:
- if (lf)
+ if (ref->lf == NULL && lf)
unlock_err = got_lockfile_unlock(lf);
if (f) {
if (fclose(f) != 0 && err == NULL)
if (err)
goto done;
- err = got_lockfile_lock(&lf, packed_refs_path);
- if (err)
- goto done;
+ if (delref->lf == NULL) {
+ err = got_lockfile_lock(&lf, packed_refs_path);
+ if (err)
+ goto done;
+ }
f = fopen(packed_refs_path, "r");
if (f == NULL) {
}
}
done:
- if (lf)
+ if (delref->lf == NULL && lf)
unlock_err = got_lockfile_unlock(lf);
if (f) {
if (fclose(f) != 0 && err == NULL)
goto done;
}
- err = got_lockfile_lock(&lf, path);
- if (err)
- goto done;
+ if (ref->lf == NULL) {
+ err = got_lockfile_lock(&lf, path);
+ if (err)
+ goto done;
+ }
/* XXX: check if old content matches our expectations? */
if (unlink(path) != 0)
err = got_error_prefix_errno2("unlink", path);
done:
- if (lf)
+ if (ref->lf == NULL && lf)
unlock_err = got_lockfile_unlock(lf);
free(path_refs);
free(path);
return err ? err : unlock_err;
}
+
+const struct got_error *
+got_ref_unlock(struct got_reference *ref)
+{
+ const struct got_error *err;
+ err = got_lockfile_unlock(ref->lf);
+ ref->lf = NULL;
+ return err;
+}
blob - bb149215b22b865bfb3a53e4acaa5b5083b9a841
blob + ef82dcbdfbbb231f2e5911319eb6ff7952e6276d
--- lib/repository.c
+++ lib/repository.c
goto done;
/* Check if the HEAD reference can be opened. */
- if (got_ref_open(&head_ref, repo, GOT_REF_HEAD) != NULL)
+ if (got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0) != NULL)
goto done;
got_ref_close(head_ref);
blob - da771a2cb37e40dc3f8acea8b76c2e5079339067
blob + ea806c36531cbc279e1c607c5ff3a998ccf0ac9a
--- lib/worktree.c
+++ lib/worktree.c
if (err)
goto done;
- err = got_ref_open(&head_ref, repo, worktree->head_ref_name);
+ err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0);
if (err)
goto done;
err = got_ref_resolve(&head_commit_id, repo, head_ref);
goto done;
/* Check if a concurrent commit to our branch has occurred. */
- /* XXX ideally we'd lock the reference file here to avoid a race */
head_ref_name = got_worktree_get_head_ref_name(worktree);
if (head_ref_name == NULL) {
err = got_error_prefix_errno("got_worktree_get_head_ref_name");
goto done;
}
- err = got_ref_open(&head_ref2, repo, head_ref_name);
+ /* Lock the reference here to prevent concurrent modification. */
+ err = got_ref_open(&head_ref2, repo, head_ref_name, 1);
if (err)
goto done;
err = got_ref_resolve(&head_commit_id2, repo, head_ref2);
goto done;
}
/* Update branch head in repository. */
- err = got_ref_change_ref(head_ref, *new_commit_id);
+ err = got_ref_change_ref(head_ref2, *new_commit_id);
if (err)
goto done;
- err = got_ref_write(head_ref, repo);
+ err = got_ref_write(head_ref2, repo);
if (err)
goto done;
- /* XXX race has ended here */
err = got_worktree_set_base_commit_id(worktree, repo, *new_commit_id);
if (err)
free(head_commit_id2);
if (head_ref)
got_ref_close(head_ref);
- if (head_ref2)
+ if (head_ref2) {
+ unlockerr = got_ref_unlock(head_ref2);
+ if (unlockerr && err == NULL)
+ err = unlockerr;
got_ref_close(head_ref2);
+ }
return err;
}
blob - 780e093cbeaf08580d0021776e1a2cdfe7e8d209
blob + 1c8251f97cb80f83b6ae8a4939b6cee9122d311d
--- regress/repository/repository_test.c
+++ regress/repository/repository_test.c
err = got_repo_open(&repo, repo_path);
if (err != NULL || repo == NULL)
return 0;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (err != NULL || head_ref == NULL)
return 0;
err = got_ref_resolve(&id, repo, head_ref);
blob - df3b5beb37efbdff4ef25f786d68a5b0f0f2663a
blob + 316594959a4c54ced16b129f9a2a60abedc9cd5e
--- regress/worktree/worktree_test.c
+++ regress/worktree/worktree_test.c
err = got_error_prefix_errno("asprintf");
goto done;
}
- err = got_ref_open(&base_ref, repo, absrefname);
+ err = got_ref_open(&base_ref, repo, absrefname, 0);
if (err)
goto done;
err = got_repo_open(&repo, repo_path);
if (err != NULL || repo == NULL)
goto done;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (err != NULL || head_ref == NULL)
goto done;
if (!obstruct_meta_file(&path, worktree_path, GOT_WORKTREE_FILE_INDEX))
return 0;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (err != NULL || head_ref == NULL)
return 0;
err = got_repo_open(&repo, repo_path);
if (err != NULL || repo == NULL)
goto done;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (err != NULL || head_ref == NULL)
goto done;
blob - c3da2f33949c3eb4e55a511d97ffeb286484f524
blob + 6513988c9c729deec721e38787c70ba0b83af0f8
--- tog/tog.c
+++ tog/tog.c
*head_id = NULL;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (err)
return err;
if (commit_id_str == NULL) {
struct got_reference *head_ref;
- error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
if (error != NULL)
goto done;
error = got_ref_resolve(&commit_id, repo, head_ref);