commit 6d9d28c32eec189b3f26c36f5510c7c4513c8ffd from: Stefan Sperling date: Sun Mar 11 01:03:45 2018 UTC implement worktree open and close operations commit - 2cb4bacb7c1ad57cef8ae02b159583485cec240d commit + 6d9d28c32eec189b3f26c36f5510c7c4513c8ffd blob - cd990563d930ce573a95bb3be8b224e54975f3bf blob + 282259e175723a16c57488d07a0e3a909a7d857c --- include/got_error.h +++ 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); blob - 39417fca0a9443677e3ab37ff1dd7a3357ef0129 blob + bf96dcd4879054c26ee1e328864c6fe76ffceaff --- lib/got_worktree_priv.h +++ 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" blob - 26980ac94f87f3f8c0a73840aca3870230a857b4 blob + 5b44fb5c530b1eb6b406a95d0f5330136258c98d --- lib/worktree.c +++ lib/worktree.c @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -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 *