commit - 2cb4bacb7c1ad57cef8ae02b159583485cec240d
commit + 6d9d28c32eec189b3f26c36f5510c7c4513c8ffd
blob - cd990563d930ce573a95bb3be8b224e54975f3bf
blob + 282259e175723a16c57488d07a0e3a909a7d857c
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_BAD_OBJ_ID_STR 23
#define GOT_ERR_WORKTREE_EXISTS 26
#define GOT_ERR_WORKTREE_META 27
+#define GOT_ERR_WORKTREE_VERS 28
+#define GOT_ERR_WORKTREE_BUSY 29
static const struct got_error {
int code;
{ GOT_ERR_BAD_OBJ_ID_STR,"bad object id string" },
{ GOT_ERR_WORKTREE_EXISTS,"worktree already exists" },
{ GOT_ERR_WORKTREE_META,"bad worktree meta data" },
+ { GOT_ERR_WORKTREE_VERS,"unsupported worktree format version" },
+ { GOT_ERR_WORKTREE_BUSY,"worktree already locked" },
};
const struct got_error * got_error(int code);
blob - 39417fca0a9443677e3ab37ff1dd7a3357ef0129
blob + bf96dcd4879054c26ee1e328864c6fe76ffceaff
--- lib/got_worktree_priv.h
+++ lib/got_worktree_priv.h
char *path_worktree_root;
char *path_repo;
char *path_prefix;
+
+ /*
+ * This file descriptor exclusively locks GOT_WORKTREE_FILE_INDEX.
+ * This ensures that only one process opens the work tree at a time.
+ */
+ int fd_fileindex;
};
#define GOT_WORKTREE_GOT_DIR ".got"
blob - 26980ac94f87f3f8c0a73840aca3870230a857b4
blob + 5b44fb5c530b1eb6b406a95d0f5330136258c98d
--- lib/worktree.c
+++ lib/worktree.c
*/
#include <sys/stat.h>
+#include <sys/limits.h>
#include <string.h>
#include <stdio.h>
const struct got_error *
got_worktree_open(struct got_worktree **worktree, const char *path)
{
- return NULL;
+ const struct got_error *err = NULL;
+ char *gotpath;
+ char *refstr = NULL;
+ char *path_repos = NULL;
+ char *formatstr = NULL;
+ char *path_fileindex = NULL;
+ int version, fd = -1;
+ const char *errstr;
+
+ *worktree = NULL;
+
+ if (asprintf(&gotpath, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) {
+ err = got_error(GOT_ERR_NO_MEM);
+ gotpath = NULL;
+ goto done;
+ }
+
+ if (asprintf(&path_fileindex, "%s/%s", gotpath,
+ GOT_WORKTREE_FILE_INDEX) == -1) {
+ err = got_error(GOT_ERR_NO_MEM);
+ path_fileindex = NULL;
+ goto done;
+ }
+
+ fd = open(path_fileindex, O_RDWR | O_EXCL | O_EXLOCK | O_NOFOLLOW,
+ GOT_DEFAULT_FILE_MODE);
+ if (fd == -1) {
+ err = got_error(GOT_ERR_WORKTREE_BUSY);
+ goto done;
+ }
+
+ err = read_meta_file(&formatstr, gotpath, GOT_WORKTREE_FORMAT);
+ if (err)
+ goto done;
+
+ version = strtonum(formatstr, 1, INT_MAX, &errstr);
+ if (errstr) {
+ err = got_error(GOT_ERR_WORKTREE_META);
+ goto done;
+ }
+ if (version != GOT_WORKTREE_FORMAT_VERSION) {
+ err = got_error(GOT_ERR_WORKTREE_VERS);
+ goto done;
+ }
+
+ *worktree = calloc(1, sizeof(**worktree));
+ if (*worktree == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ (*worktree)->fd_fileindex = -1;
+
+ (*worktree)->path_worktree_root = strdup(path);
+ if ((*worktree)->path_worktree_root == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ err = read_meta_file(&(*worktree)->path_repo, gotpath,
+ GOT_WORKTREE_REPOSITORY);
+ if (err)
+ goto done;
+ err = read_meta_file(&(*worktree)->path_prefix, gotpath,
+ GOT_WORKTREE_PATH_PREFIX);
+ goto done;
+
+done:
+ free(gotpath);
+ free(path_fileindex);
+ if (err) {
+ if (fd != -1)
+ close(fd);
+ if (*worktree != NULL)
+ got_worktree_close(*worktree);
+ *worktree = NULL;
+ } else
+ (*worktree)->fd_fileindex = fd;
+
+ return err;
}
void
got_worktree_close(struct got_worktree *worktree)
{
+ free(worktree->path_worktree_root);
+ free(worktree->path_repo);
+ free(worktree->path_prefix);
+ if (worktree->fd_fileindex != -1)
+ close(worktree->fd_fileindex);
+ free(worktree);
}
char *