implement worktree open and close operations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
diff --git a/include/got_error.h b/include/got_error.h
index cd99056..282259e 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -41,6 +41,8 @@
#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;
@@ -72,6 +74,8 @@ static const struct got_error {
{ 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);
diff --git a/lib/got_worktree_priv.h b/lib/got_worktree_priv.h
index 39417fc..bf96dcd 100644
--- a/lib/got_worktree_priv.h
+++ b/lib/got_worktree_priv.h
@@ -18,6 +18,12 @@ struct got_worktree {
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"
diff --git a/lib/worktree.c b/lib/worktree.c
index 26980ac..5b44fb5 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -15,6 +15,7 @@
*/
#include <sys/stat.h>
+#include <sys/limits.h>
#include <string.h>
#include <stdio.h>
@@ -207,12 +208,95 @@ done:
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 *