Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "sysdir.h"
9 -
10 - #include "global.h"
11 - #include "buffer.h"
12 - #include "path.h"
13 - #include <ctype.h>
14 - #if GIT_WIN32
15 - #include "win32/findfile.h"
16 - #else
17 - #include <unistd.h>
18 - #include <pwd.h>
19 - #endif
20 -
21 9 2 static int git_sysdir_guess_programdata_dirs(git_buf *out)
22 - {
23 - #ifdef GIT_WIN32
24 - return git_win32__find_programdata_dirs(out);
25 - #else
26 9 2 git_buf_clear(out);
27 9 3 return 0;
28 - #endif
29 - }
30 -
31 10 2 static int git_sysdir_guess_system_dirs(git_buf *out)
32 - {
33 - #ifdef GIT_WIN32
34 - return git_win32__find_system_dirs(out, L"etc\\");
35 - #else
36 10 2 return git_buf_sets(out, "/etc");
37 - #endif
38 - }
39 -
40 - #ifndef GIT_WIN32
41 ##### 2 static int get_passwd_home(git_buf *out, uid_t uid)
42 - {
43 - struct passwd pwd, *pwdptr;
44 ##### 2 char *buf = NULL;
45 - long buflen;
46 - int error;
47 -
48 ##### 2,3 assert(out);
49 -
50 ##### 4,5 if ((buflen = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1)
51 ##### 6 buflen = 1024;
52 -
53 - do {
54 ##### 7 buf = git__realloc(buf, buflen);
55 ##### 8 error = getpwuid_r(uid, &pwd, buf, buflen, &pwdptr);
56 ##### 9 buflen *= 2;
57 ##### 9,10 } while (error == ERANGE && buflen <= 8192);
58 -
59 ##### 11 if (error) {
60 ##### 12 git_error_set(GIT_ERROR_OS, "failed to get passwd entry");
61 ##### 13 goto out;
62 - }
63 -
64 ##### 14 if (!pwdptr) {
65 ##### 15 git_error_set(GIT_ERROR_OS, "no passwd entry found for user");
66 ##### 16 goto out;
67 - }
68 -
69 ##### 17,18 if ((error = git_buf_puts(out, pwdptr->pw_dir)) < 0)
70 ##### 19 goto out;
71 -
72 - out:
73 ##### 20 git__free(buf);
74 ##### 21 return error;
75 - }
76 - #endif
77 -
78 51 2 static int git_sysdir_guess_global_dirs(git_buf *out)
79 - {
80 - #ifdef GIT_WIN32
81 - return git_win32__find_global_dirs(out);
82 - #else
83 - int error;
84 - uid_t uid, euid;
85 - const char *sandbox_id;
86 -
87 51 2 uid = getuid();
88 51 3 euid = geteuid();
89 -
90 - /**
91 - * If APP_SANDBOX_CONTAINER_ID is set, we are running in a
92 - * sandboxed environment on macOS.
93 - */
94 51 4 sandbox_id = getenv("APP_SANDBOX_CONTAINER_ID");
95 -
96 - /*
97 - * In case we are running setuid, use the configuration
98 - * of the effective user.
99 - *
100 - * If we are running in a sandboxed environment on macOS,
101 - * we have to get the HOME dir from the password entry file.
102 - */
103 51 5,6 if (!sandbox_id && uid == euid)
104 51 7 error = git__getenv(out, "HOME");
105 - else
106 ##### 8 error = get_passwd_home(out, euid);
107 -
108 51 9 if (error == GIT_ENOTFOUND) {
109 1 10 git_error_clear();
110 1 11 error = 0;
111 - }
112 -
113 51 12 return error;
114 - #endif
115 - }
116 -
117 9 2 static int git_sysdir_guess_xdg_dirs(git_buf *out)
118 - {
119 - #ifdef GIT_WIN32
120 - return git_win32__find_xdg_dirs(out);
121 - #else
122 9 2 git_buf env = GIT_BUF_INIT;
123 - int error;
124 - uid_t uid, euid;
125 -
126 9 2 uid = getuid();
127 9 3 euid = geteuid();
128 -
129 - /*
130 - * In case we are running setuid, only look up passwd
131 - * directory of the effective user.
132 - */
133 9 4 if (uid == euid) {
134 9 5,6 if ((error = git__getenv(&env, "XDG_CONFIG_HOME")) == 0)
135 ##### 7 error = git_buf_joinpath(out, env.ptr, "git");
136 -
137 9 8-10 if (error == GIT_ENOTFOUND && (error = git__getenv(&env, "HOME")) == 0)
138 9 11,12 error = git_buf_joinpath(out, env.ptr, ".config/git");
139 - } else {
140 ##### 13,14 if ((error = get_passwd_home(&env, euid)) == 0)
141 ##### 15 error = git_buf_joinpath(out, env.ptr, ".config/git");
142 - }
143 -
144 9 16 if (error == GIT_ENOTFOUND) {
145 ##### 17 git_error_clear();
146 ##### 18 error = 0;
147 - }
148 -
149 9 19 git_buf_dispose(&env);
150 9 20 return error;
151 - #endif
152 - }
153 -
154 9 2 static int git_sysdir_guess_template_dirs(git_buf *out)
155 - {
156 - #ifdef GIT_WIN32
157 - return git_win32__find_system_dirs(out, L"share\\git-core\\templates");
158 - #else
159 9 2 return git_buf_sets(out, "/usr/share/git-core/templates");
160 - #endif
161 - }
162 -
163 - struct git_sysdir__dir {
164 - git_buf buf;
165 - int (*guess)(git_buf *out);
166 - };
167 -
168 - static struct git_sysdir__dir git_sysdir__dirs[] = {
169 - { GIT_BUF_INIT, git_sysdir_guess_system_dirs },
170 - { GIT_BUF_INIT, git_sysdir_guess_global_dirs },
171 - { GIT_BUF_INIT, git_sysdir_guess_xdg_dirs },
172 - { GIT_BUF_INIT, git_sysdir_guess_programdata_dirs },
173 - { GIT_BUF_INIT, git_sysdir_guess_template_dirs },
174 - };
175 -
176 9 2 static void git_sysdir_global_shutdown(void)
177 - {
178 - size_t i;
179 -
180 54 2,4,5 for (i = 0; i < ARRAY_SIZE(git_sysdir__dirs); ++i)
181 45 3 git_buf_dispose(&git_sysdir__dirs[i].buf);
182 9 6 }
183 -
184 9 2 int git_sysdir_global_init(void)
185 - {
186 - size_t i;
187 9 2 int error = 0;
188 -
189 54 2,4-6 for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++)
190 45 3 error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf);
191 -
192 9 7 git__on_shutdown(git_sysdir_global_shutdown);
193 -
194 9 8 return error;
195 - }
196 -
197 119177 2 static int git_sysdir_check_selector(git_sysdir_t which)
198 - {
199 119177 2 if (which < ARRAY_SIZE(git_sysdir__dirs))
200 119177 3 return 0;
201 -
202 ##### 4 git_error_set(GIT_ERROR_INVALID, "config directory selector out of range");
203 ##### 5 return -1;
204 - }
205 -
206 -
207 118806 2 int git_sysdir_get(const git_buf **out, git_sysdir_t which)
208 - {
209 118806 2,3 assert(out);
210 -
211 118806 4 *out = NULL;
212 -
213 118812 4-6 GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which));
214 -
215 118812 7 *out = &git_sysdir__dirs[which].buf;
216 118812 7 return 0;
217 - }
218 -
219 - #define PATH_MAGIC "$PATH"
220 -
221 369 2 int git_sysdir_set(git_sysdir_t which, const char *search_path)
222 - {
223 369 2 const char *expand_path = NULL;
224 369 2 git_buf merge = GIT_BUF_INIT;
225 -
226 369 2-4 GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which));
227 -
228 369 5 if (search_path != NULL)
229 326 6 expand_path = strstr(search_path, PATH_MAGIC);
230 -
231 - /* reset the default if this path has been cleared */
232 369 7 if (!search_path)
233 43 8 git_sysdir__dirs[which].guess(&git_sysdir__dirs[which].buf);
234 -
235 - /* if $PATH is not referenced, then just set the path */
236 369 9 if (!expand_path) {
237 352 10 if (search_path)
238 309 11 git_buf_sets(&git_sysdir__dirs[which].buf, search_path);
239 -
240 352 12 goto done;
241 - }
242 -
243 - /* otherwise set to join(before $PATH, old value, after $PATH) */
244 17 13 if (expand_path > search_path)
245 8 14 git_buf_set(&merge, search_path, expand_path - search_path);
246 -
247 17 15,16 if (git_buf_len(&git_sysdir__dirs[which].buf))
248 17 17 git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR,
249 17 17 merge.ptr, git_sysdir__dirs[which].buf.ptr);
250 -
251 17 18 expand_path += strlen(PATH_MAGIC);
252 17 18 if (*expand_path)
253 9 19 git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path);
254 -
255 17 20 git_buf_swap(&git_sysdir__dirs[which].buf, &merge);
256 17 21 git_buf_dispose(&merge);
257 -
258 - done:
259 369 22,23 if (git_buf_oom(&git_sysdir__dirs[which].buf))
260 ##### 24 return -1;
261 -
262 369 25 return 0;
263 - }
264 -
265 - 2 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files)static int git_sysdir_find_in_dirlist(
266 - git_buf *path,
267 - const char *name,
268 - git_sysdir_t which,
269 - const char *label)
270 - {
271 - size_t len;
272 - 2 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) const char *scan, *next = NULL;
273 - const git_buf *syspath;
274 -
275 - 2-4 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ERROR(git_sysdir_get(&syspath, which));
276 - 5-7 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (!syspath || !git_buf_len(syspath))
277 - goto done;
278 -
279 - 8,30,31 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) for (scan = git_buf_cstr(syspath); scan; scan = next) {
280 - /* find unescaped separator or end of string */
281 - 9,13,14 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) for (next = scan; *next; ++next) {
282 - 10,11 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (*next == GIT_PATH_LIST_SEPARATOR &&
283 - 12 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) (next <= scan || next[-1] != '\\'))
284 - break;
285 - }
286 -
287 - 15 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) len = (size_t)(next - scan);
288 - 15-17 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) next = (*next ? next + 1 : NULL);
289 - 18 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (!len)
290 - 19 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) continue;
291 -
292 - 20-22 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ERROR(git_buf_set(path, scan, len));
293 - 23 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (name)
294 - 24-26 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name));
295 -
296 - 27,28 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (git_path_exists(path->ptr))
297 - 29 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) return 0;
298 - }
299 -
300 - done:
301 - 32 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) git_buf_dispose(path);
302 - 33 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) git_error_set(GIT_ERROR_OS, "the %s file '%s' doesn't exist", label, name);
303 - 34 suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) return GIT_ENOTFOUND;
304 - }
305 -
306 99751 2 int git_sysdir_find_system_file(git_buf *path, const char *filename)
307 - {
308 99751 2 return git_sysdir_find_in_dirlist(
309 - path, filename, GIT_SYSDIR_SYSTEM, "system");
310 - }
311 -
312 4184 2 int git_sysdir_find_global_file(git_buf *path, const char *filename)
313 - {
314 4184 2 return git_sysdir_find_in_dirlist(
315 - path, filename, GIT_SYSDIR_GLOBAL, "global");
316 - }
317 -
318 6646 2 int git_sysdir_find_xdg_file(git_buf *path, const char *filename)
319 - {
320 6646 2 return git_sysdir_find_in_dirlist(
321 - path, filename, GIT_SYSDIR_XDG, "global/xdg");
322 - }
323 -
324 4090 2 int git_sysdir_find_programdata_file(git_buf *path, const char *filename)
325 - {
326 4090 2 return git_sysdir_find_in_dirlist(
327 - path, filename, GIT_SYSDIR_PROGRAMDATA, "ProgramData");
328 - }
329 -
330 ##### 2 int git_sysdir_find_template_dir(git_buf *path)
331 - {
332 ##### 2 return git_sysdir_find_in_dirlist(
333 - path, NULL, GIT_SYSDIR_TEMPLATE, "template");
334 - }
335 -
336 9 2 int git_sysdir_expand_global_file(git_buf *path, const char *filename)
337 - {
338 - int error;
339 -
340 9 2,3 if ((error = git_sysdir_find_global_file(path, NULL)) == 0) {
341 9 4 if (filename)
342 8 5 error = git_buf_joinpath(path, path->ptr, filename);
343 - }
344 -
345 9 6 return error;
346 - }