commit - 58ecc593d87b44c67285aa8e2fb9ae755dcb212a
commit + 056e7441d0bdfa8d8f7b240b34841190cf1864b4
blob - 7a450583547cf98b71421a004139b893da9708a7
blob + 621a020293d6051bf22facd02ba75e02d422ba59
--- lib/got_worktree_priv.h
+++ lib/got_worktree_priv.h
char *path_prefix;
/*
- * File descriptor for the file index, open while a work tree is open.
- * This is used to read the file index and to write out a new file
- * index, and also for locking the entire work tree.
- * When a work tree is opened, a shared lock on the file index is
+ * File descriptor for the lock file, open while a work tree is open.
+ * When a work tree is opened, a shared lock on the lock file is
* acquired with flock(2). This shared lock is held until the work
* tree is closed, i.e. throughout the lifetime of any operation
* which uses a work tree.
- * Before any modifications are made to the on-disk state of meta data,
- * tracked files, or directory tree structure, this shared lock must
- * be upgraded to an exclusive lock.
+ * Before any modifications are made to the on-disk state of work
+ * tree meta data, tracked files, or directory tree structure, this
+ * shared lock must be upgraded to an exclusive lock.
*/
- int fd_fileindex;
+ int lockfd;
};
#define GOT_WORKTREE_GOT_DIR ".got"
#define GOT_WORKTREE_FILE_INDEX "fileindex"
#define GOT_WORKTREE_REPOSITORY "repository"
#define GOT_WORKTREE_PATH_PREFIX "path-prefix"
+#define GOT_WORKTREE_LOCK "lock"
#define GOT_WORKTREE_FORMAT "format"
#define GOT_WORKTREE_FORMAT_VERSION 1
blob - 04c8fc0fc3ec37db221182a522c6955555eec78b
blob + cdfcd000a8660c94d153db4902677bbfc283eafa
--- lib/worktree.c
+++ lib/worktree.c
goto done;
}
+ /* Create an empty lock file. */
+ err = create_meta_file(gotpath, GOT_WORKTREE_LOCK, NULL);
+ if (err)
+ goto done;
+
/* Create an empty file index. */
err = create_meta_file(gotpath, GOT_WORKTREE_FILE_INDEX, NULL);
if (err)
char *refstr = NULL;
char *path_repos = NULL;
char *formatstr = NULL;
- char *path_fileindex = NULL;
+ char *path_lock = NULL;
int version, fd = -1;
const char *errstr;
goto done;
}
- if (asprintf(&path_fileindex, "%s/%s", gotpath,
- GOT_WORKTREE_FILE_INDEX) == -1) {
+ if (asprintf(&path_lock, "%s/%s", gotpath, GOT_WORKTREE_LOCK) == -1) {
err = got_error(GOT_ERR_NO_MEM);
- path_fileindex = NULL;
+ path_lock = NULL;
goto done;
}
- fd = open(path_fileindex, O_RDWR | O_NOFOLLOW, GOT_DEFAULT_FILE_MODE);
+ fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK);
if (fd == -1) {
- err = got_error_from_errno();
- goto done;
- }
- if (flock(fd, LOCK_SH | LOCK_NB) == -1) {
err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY)
: got_error_from_errno());
goto done;
err = got_error(GOT_ERR_NO_MEM);
goto done;
}
- (*worktree)->fd_fileindex = -1;
+ (*worktree)->lockfd = -1;
(*worktree)->path_worktree_root = strdup(path);
if ((*worktree)->path_worktree_root == NULL) {
done:
free(gotpath);
- free(path_fileindex);
+ free(path_lock);
if (err) {
if (fd != -1)
close(fd);
got_worktree_close(*worktree);
*worktree = NULL;
} else
- (*worktree)->fd_fileindex = fd;
+ (*worktree)->lockfd = fd;
return err;
}
free(worktree->path_worktree_root);
free(worktree->path_repo);
free(worktree->path_prefix);
- if (worktree->fd_fileindex != -1)
- close(worktree->fd_fileindex);
+ if (worktree->lockfd != -1)
+ close(worktree->lockfd);
free(worktree);
}
blob - ec99a28c1c9c643626df9ed7c9de996380b31425
blob + b6bb45f3bb8490bef65f1913b4597ca9ec45db21
--- regress/worktree/worktree_test.c
+++ regress/worktree/worktree_test.c
remove_meta_file(worktree_path, GOT_WORKTREE_FILE_INDEX);
remove_meta_file(worktree_path, GOT_WORKTREE_REPOSITORY);
remove_meta_file(worktree_path, GOT_WORKTREE_PATH_PREFIX);
+ remove_meta_file(worktree_path, GOT_WORKTREE_LOCK);
remove_meta_file(worktree_path, GOT_WORKTREE_FORMAT);
remove_got_dir(worktree_path);
rmdir(worktree_path);
/* Ensure required files were created. */
if (!check_meta_file_exists(worktree_path, GOT_REF_HEAD))
goto done;
+ if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_LOCK))
+ goto done;
if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_FILE_INDEX))
goto done;
if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_REPOSITORY))
unlink(path);
free(path);
+ if (!obstruct_meta_file(&path, worktree_path, GOT_WORKTREE_LOCK))
+ goto done;
+ err = got_worktree_init(worktree_path, head_ref, "/", repo);
+ if (err != NULL && err->code == GOT_ERR_ERRNO && errno == EEXIST)
+ ok++;
+ unlink(path);
+ free(path);
+
if (!obstruct_meta_file(&path, worktree_path, GOT_WORKTREE_FILE_INDEX))
goto done;
err = got_worktree_init(worktree_path, head_ref, "/", repo);
if (repo)
got_repo_close(repo);
free(gotpath);
- if (ok == 5)
+ if (ok == 6)
remove_workdir(worktree_path);
- return (ok == 5);
+ return (ok == 6);
}
#define RUN_TEST(expr, name) \