Blob


1 /*
2 * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
3 *
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.
7 *
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.
15 */
17 #include <sys/stat.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <unistd.h>
26 #include "got_error.h"
27 #include "got_repository.h"
28 #include "got_refs.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)
37 {
38 const struct got_error *err = NULL;
39 char *abspath = NULL;
40 char *normpath = NULL;
41 char *gotpath = NULL;
42 char *indexpath = NULL;
43 char *headpath = NULL;
44 char *repopath = NULL;
45 char *refstr = NULL;
46 char *path_repos = NULL;
47 char buf[4];
48 ssize_t n;
49 int fd;
51 if (got_path_is_absolute(path)) {
52 abspath = strdup(path);
53 if (abspath == NULL)
54 return got_error(GOT_ERR_NO_MEM);
55 } else {
56 abspath = got_path_get_absolute(path);
57 if (abspath == NULL)
58 return got_error(GOT_ERR_BAD_PATH);
59 }
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);
65 goto done;
66 }
67 if (mkdir(normpath, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
68 err = got_error_from_errno();
69 goto done;
70 }
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);
75 goto done;
76 }
77 if (mkdir(gotpath, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
78 err = got_error_from_errno();
79 goto done;
80 }
82 /* Create an empty file index. */
83 if (asprintf(&indexpath, "%s/%s", gotpath, GOT_WORKTREE_FILE_INDEX)
84 == -1) {
85 err = got_error(GOT_ERR_NO_MEM);
86 goto done;
87 }
88 fd = open(indexpath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
89 GOT_DEFAULT_FILE_MODE);
90 if (fd == -1) {
91 err = got_error_from_errno();
92 goto done;
93 }
94 n = read(fd, buf, sizeof(buf));
95 if (n != 0) {
96 err = (n == -1 ? got_error_from_errno() :
97 got_error(GOT_ERR_WORKTREE_EXISTS));
98 close(fd);
99 goto done;
101 if (close(fd) == -1) {
102 err = got_error_from_errno();
103 goto done;
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);
110 goto done;
112 if (asprintf(&headpath, "%s/%s", gotpath, GOT_REF_HEAD) == -1) {
113 err = got_error(GOT_ERR_NO_MEM);
114 goto done;
116 fd = open(headpath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
117 GOT_DEFAULT_FILE_MODE);
118 if (fd == -1) {
119 err = got_error_from_errno();
120 goto done;
122 n = read(fd, buf, sizeof(buf));
123 if (n != 0) {
124 err = (n == -1 ? got_error_from_errno() :
125 got_error(GOT_ERR_WORKTREE_EXISTS));
126 close(fd);
127 goto done;
129 n = write(fd, refstr, strlen(refstr));
130 if (n != strlen(refstr)) {
131 err = got_error_from_errno();
132 close(fd);
133 goto done;
135 n = write(fd, "\n", 1);
136 if (n != 1) {
137 err = got_error_from_errno();
138 close(fd);
139 goto done;
141 if (close(fd) == -1) {
142 err = got_error_from_errno();
143 goto done;
146 /* Store path to repository. */
147 if (asprintf(&repopath, "%s/%s", gotpath, GOT_WORKTREE_REPOSITORY)
148 == -1) {
149 err = got_error(GOT_ERR_NO_MEM);
150 goto done;
152 fd = open(repopath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
153 GOT_DEFAULT_FILE_MODE);
154 if (fd == -1) {
155 err = got_error_from_errno();
156 goto done;
158 n = read(fd, buf, sizeof(buf));
159 if (n != 0) {
160 err = (n == -1 ? got_error_from_errno() :
161 got_error(GOT_ERR_WORKTREE_EXISTS));
162 close(fd);
163 goto done;
165 path_repos = got_repo_get_path(repo);
166 if (path_repos == NULL) {
167 err = got_error(GOT_ERR_NO_MEM);
168 goto done;
170 n = write(fd, path_repos, strlen(path_repos));
171 if (n != strlen(path_repos)) {
172 err = got_error_from_errno();
173 close(fd);
174 goto done;
176 n = write(fd, "\n", 1);
177 if (n != 1) {
178 err = got_error_from_errno();
179 close(fd);
180 goto done;
182 if (close(fd) == -1) {
183 err = got_error_from_errno();
184 goto done;
187 done:
188 free(abspath);
189 free(normpath);
190 free(gotpath);
191 free(indexpath);
192 free(headpath);
193 free(repopath);
194 free(refstr);
195 free(path_repos);
196 return err;
199 const struct got_error *
200 got_worktree_open(struct got_worktree **worktree, const char *path)
202 return NULL;
205 void
206 got_worktree_close(struct got_worktree *worktree)
210 char *
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)
219 return NULL;
222 const struct got_error *
223 got_worktree_set_head(struct got_worktree *worktree, struct got_reference *head,
224 struct got_repository *repo)
226 return NULL;
229 const struct got_error *
230 got_worktree_checkout_files(struct got_worktree *worktree,
231 struct got_repository *repo)
233 return NULL;