2 * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 #include "got_error.h"
27 #include "got_repository.h"
29 #include "got_worktree.h"
31 #include "got_worktree_priv.h"
32 #include "got_path_priv.h"
34 const struct got_error *
35 got_worktree_init(const char *path, struct got_reference *head_ref,
36 struct got_repository *repo)
38 const struct got_error *err = NULL;
40 char *normpath = NULL;
42 char *indexpath = NULL;
43 char *headpath = NULL;
44 char *repopath = NULL;
46 char *path_repos = NULL;
51 if (got_path_is_absolute(path)) {
52 abspath = strdup(path);
54 return got_error(GOT_ERR_NO_MEM);
56 abspath = got_path_get_absolute(path);
58 return got_error(GOT_ERR_BAD_PATH);
61 /* Create top-level directory (may already exist). */
62 normpath = got_path_normalize(abspath);
63 if (normpath == NULL) {
64 err = got_error(GOT_ERR_BAD_PATH);
67 if (mkdir(normpath, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
68 err = got_error_from_errno();
72 /* Create .got directory (may already exist). */
73 if (asprintf(&gotpath, "%s/%s", normpath, GOT_WORKTREE_GOT_DIR) == -1) {
74 err = got_error(GOT_ERR_NO_MEM);
77 if (mkdir(gotpath, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
78 err = got_error_from_errno();
82 /* Create an empty file index. */
83 if (asprintf(&indexpath, "%s/%s", gotpath, GOT_WORKTREE_FILE_INDEX)
85 err = got_error(GOT_ERR_NO_MEM);
88 fd = open(indexpath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
89 GOT_DEFAULT_FILE_MODE);
91 err = got_error_from_errno();
94 n = read(fd, buf, sizeof(buf));
96 err = (n == -1 ? got_error_from_errno() :
97 got_error(GOT_ERR_WORKTREE_EXISTS));
101 if (close(fd) == -1) {
102 err = got_error_from_errno();
106 /* Write the HEAD reference. */
107 refstr = got_ref_to_str(head_ref);
108 if (refstr == NULL) {
109 err = got_error(GOT_ERR_NO_MEM);
112 if (asprintf(&headpath, "%s/%s", gotpath, GOT_REF_HEAD) == -1) {
113 err = got_error(GOT_ERR_NO_MEM);
116 fd = open(headpath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
117 GOT_DEFAULT_FILE_MODE);
119 err = got_error_from_errno();
122 n = read(fd, buf, sizeof(buf));
124 err = (n == -1 ? got_error_from_errno() :
125 got_error(GOT_ERR_WORKTREE_EXISTS));
129 n = write(fd, refstr, strlen(refstr));
130 if (n != strlen(refstr)) {
131 err = got_error_from_errno();
135 n = write(fd, "\n", 1);
137 err = got_error_from_errno();
141 if (close(fd) == -1) {
142 err = got_error_from_errno();
146 /* Store path to repository. */
147 if (asprintf(&repopath, "%s/%s", gotpath, GOT_WORKTREE_REPOSITORY) == -1) {
148 err = got_error(GOT_ERR_NO_MEM);
151 fd = open(repopath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
152 GOT_DEFAULT_FILE_MODE);
154 err = got_error_from_errno();
157 n = read(fd, buf, sizeof(buf));
159 err = (n == -1 ? got_error_from_errno() :
160 got_error(GOT_ERR_WORKTREE_EXISTS));
164 path_repos = got_repo_get_path(repo);
165 if (path_repos == NULL) {
166 err = got_error(GOT_ERR_NO_MEM);
169 n = write(fd, path_repos, strlen(path_repos));
170 if (n != strlen(path_repos)) {
171 err = got_error_from_errno();
175 n = write(fd, "\n", 1);
177 err = got_error_from_errno();
181 if (close(fd) == -1) {
182 err = got_error_from_errno();
198 const struct got_error *
199 got_worktree_open(struct got_worktree **worktree, const char *path)
205 got_worktree_close(struct got_worktree *worktree)
210 got_worktree_get_repo_path(struct got_worktree *worktree)
212 return strdup(worktree->path_repo);
215 struct got_reference *
216 got_worktree_get_head(struct got_worktree *worktree)
221 const struct got_error *
222 got_worktree_set_head(struct got_worktree *worktree, struct got_reference *head,
223 struct got_repository *repo)
228 const struct got_error *
229 got_worktree_checkout_files(struct got_worktree *worktree,
230 struct got_repository *repo)