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)
149 err = got_error(GOT_ERR_NO_MEM);
152 fd = open(repopath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
153 GOT_DEFAULT_FILE_MODE);
155 err = got_error_from_errno();
158 n = read(fd, buf, sizeof(buf));
160 err = (n == -1 ? got_error_from_errno() :
161 got_error(GOT_ERR_WORKTREE_EXISTS));
165 path_repos = got_repo_get_path(repo);
166 if (path_repos == NULL) {
167 err = got_error(GOT_ERR_NO_MEM);
170 n = write(fd, path_repos, strlen(path_repos));
171 if (n != strlen(path_repos)) {
172 err = got_error_from_errno();
176 n = write(fd, "\n", 1);
178 err = got_error_from_errno();
182 if (close(fd) == -1) {
183 err = got_error_from_errno();
199 const struct got_error *
200 got_worktree_open(struct got_worktree **worktree, const char *path)
206 got_worktree_close(struct got_worktree *worktree)
211 got_worktree_get_repo_path(struct got_worktree *worktree)
213 return strdup(worktree->path_repo);
216 struct got_reference *
217 got_worktree_get_head(struct got_worktree *worktree)
222 const struct got_error *
223 got_worktree_set_head(struct got_worktree *worktree, struct got_reference *head,
224 struct got_repository *repo)
229 const struct got_error *
230 got_worktree_checkout_files(struct got_worktree *worktree,
231 struct got_repository *repo)