2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
15 #include "win32/findfile.h"
18 static int git_sysdir_guess_system_dirs(git_buf
*out
)
21 return git_win32__find_system_dirs(out
, L
"etc\\");
23 return git_buf_sets(out
, "/etc");
27 static int git_sysdir_guess_global_dirs(git_buf
*out
)
30 return git_win32__find_global_dirs(out
);
32 return git_buf_sets(out
, getenv("HOME"));
36 static int git_sysdir_guess_xdg_dirs(git_buf
*out
)
39 return git_win32__find_xdg_dirs(out
);
41 const char *env
= NULL
;
43 if ((env
= getenv("XDG_CONFIG_HOME")) != NULL
)
44 return git_buf_joinpath(out
, env
, "git");
45 else if ((env
= getenv("HOME")) != NULL
)
46 return git_buf_joinpath(out
, env
, ".config/git");
53 static int git_sysdir_guess_template_dirs(git_buf
*out
)
56 return git_win32__find_system_dirs(out
, L
"share\\git-core\\templates");
58 return git_buf_sets(out
, "/usr/share/git-core/templates");
62 typedef int (*git_sysdir_guess_cb
)(git_buf
*out
);
64 static git_buf git_sysdir__dirs
[GIT_SYSDIR__MAX
] =
65 { GIT_BUF_INIT
, GIT_BUF_INIT
, GIT_BUF_INIT
, GIT_BUF_INIT
};
67 static git_sysdir_guess_cb git_sysdir__dir_guess
[GIT_SYSDIR__MAX
] = {
68 git_sysdir_guess_system_dirs
,
69 git_sysdir_guess_global_dirs
,
70 git_sysdir_guess_xdg_dirs
,
71 git_sysdir_guess_template_dirs
,
74 static int git_sysdir__dirs_shutdown_set
= 0;
76 int git_sysdir_global_init(void)
82 for (i
= 0; !error
&& i
< GIT_SYSDIR__MAX
; i
++)
83 error
= git_sysdir_get(&path
, i
);
88 void git_sysdir_global_shutdown(void)
91 for (i
= 0; i
< GIT_SYSDIR__MAX
; ++i
)
92 git_buf_free(&git_sysdir__dirs
[i
]);
94 git_sysdir__dirs_shutdown_set
= 0;
97 static int git_sysdir_check_selector(git_sysdir_t which
)
99 if (which
< GIT_SYSDIR__MAX
)
102 giterr_set(GITERR_INVALID
, "config directory selector out of range");
107 int git_sysdir_get(const git_buf
**out
, git_sysdir_t which
)
113 GITERR_CHECK_ERROR(git_sysdir_check_selector(which
));
115 if (!git_buf_len(&git_sysdir__dirs
[which
])) {
116 /* prepare shutdown if we're going to need it */
117 if (!git_sysdir__dirs_shutdown_set
) {
118 git__on_shutdown(git_sysdir_global_shutdown
);
119 git_sysdir__dirs_shutdown_set
= 1;
123 git_sysdir__dir_guess
[which
](&git_sysdir__dirs
[which
]));
126 *out
= &git_sysdir__dirs
[which
];
130 int git_sysdir_get_str(
135 const git_buf
*path
= NULL
;
137 GITERR_CHECK_ERROR(git_sysdir_check_selector(which
));
138 GITERR_CHECK_ERROR(git_sysdir_get(&path
, which
));
140 if (!out
|| path
->size
>= outlen
) {
141 giterr_set(GITERR_NOMEMORY
, "Buffer is too short for the path");
145 git_buf_copy_cstr(out
, outlen
, path
);
149 #define PATH_MAGIC "$PATH"
151 int git_sysdir_set(git_sysdir_t which
, const char *search_path
)
153 const char *expand_path
= NULL
;
154 git_buf merge
= GIT_BUF_INIT
;
156 GITERR_CHECK_ERROR(git_sysdir_check_selector(which
));
158 if (search_path
!= NULL
)
159 expand_path
= strstr(search_path
, PATH_MAGIC
);
161 /* init with default if not yet done and needed (ignoring error) */
162 if ((!search_path
|| expand_path
) &&
163 !git_buf_len(&git_sysdir__dirs
[which
]))
164 git_sysdir__dir_guess
[which
](&git_sysdir__dirs
[which
]);
166 /* if $PATH is not referenced, then just set the path */
168 return git_buf_sets(&git_sysdir__dirs
[which
], search_path
);
170 /* otherwise set to join(before $PATH, old value, after $PATH) */
171 if (expand_path
> search_path
)
172 git_buf_set(&merge
, search_path
, expand_path
- search_path
);
174 if (git_buf_len(&git_sysdir__dirs
[which
]))
175 git_buf_join(&merge
, GIT_PATH_LIST_SEPARATOR
,
176 merge
.ptr
, git_sysdir__dirs
[which
].ptr
);
178 expand_path
+= strlen(PATH_MAGIC
);
180 git_buf_join(&merge
, GIT_PATH_LIST_SEPARATOR
, merge
.ptr
, expand_path
);
182 git_buf_swap(&git_sysdir__dirs
[which
], &merge
);
183 git_buf_free(&merge
);
185 return git_buf_oom(&git_sysdir__dirs
[which
]) ? -1 : 0;
188 static int git_sysdir_find_in_dirlist(
195 const char *scan
, *next
= NULL
;
196 const git_buf
*syspath
;
198 GITERR_CHECK_ERROR(git_sysdir_get(&syspath
, which
));
199 if (!syspath
|| !git_buf_len(syspath
))
202 for (scan
= git_buf_cstr(syspath
); scan
; scan
= next
) {
203 /* find unescaped separator or end of string */
204 for (next
= scan
; *next
; ++next
) {
205 if (*next
== GIT_PATH_LIST_SEPARATOR
&&
206 (next
<= scan
|| next
[-1] != '\\'))
210 len
= (size_t)(next
- scan
);
211 next
= (*next
? next
+ 1 : NULL
);
215 GITERR_CHECK_ERROR(git_buf_set(path
, scan
, len
));
217 GITERR_CHECK_ERROR(git_buf_joinpath(path
, path
->ptr
, name
));
219 if (git_path_exists(path
->ptr
))
225 giterr_set(GITERR_OS
, "The %s file '%s' doesn't exist", label
, name
);
226 return GIT_ENOTFOUND
;
229 int git_sysdir_find_system_file(git_buf
*path
, const char *filename
)
231 return git_sysdir_find_in_dirlist(
232 path
, filename
, GIT_SYSDIR_SYSTEM
, "system");
235 int git_sysdir_find_global_file(git_buf
*path
, const char *filename
)
237 return git_sysdir_find_in_dirlist(
238 path
, filename
, GIT_SYSDIR_GLOBAL
, "global");
241 int git_sysdir_find_xdg_file(git_buf
*path
, const char *filename
)
243 return git_sysdir_find_in_dirlist(
244 path
, filename
, GIT_SYSDIR_XDG
, "global/xdg");
247 int git_sysdir_find_template_dir(git_buf
*path
)
249 return git_sysdir_find_in_dirlist(
250 path
, NULL
, GIT_SYSDIR_TEMPLATE
, "template");