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 "libgit2.h"
9 
10 #include <git2.h>
11 #include "alloc.h"
12 #include "cache.h"
13 #include "common.h"
14 #include "filter.h"
15 #include "hash.h"
16 #include "index.h"
17 #include "merge_driver.h"
18 #include "pool.h"
19 #include "mwindow.h"
20 #include "object.h"
21 #include "odb.h"
22 #include "refs.h"
23 #include "runtime.h"
24 #include "sysdir.h"
25 #include "thread.h"
26 #include "threadstate.h"
27 #include "git2/global.h"
28 #include "streams/registry.h"
29 #include "streams/mbedtls.h"
30 #include "streams/openssl.h"
31 #include "transports/smart.h"
32 #include "transports/http.h"
33 #include "transports/ssh.h"
34 
35 #ifdef GIT_WIN32
36 # include "win32/w32_leakcheck.h"
37 #endif
38 
39 /* Declarations for tuneable settings */
40 extern size_t git_mwindow__window_size;
41 extern size_t git_mwindow__mapped_limit;
42 extern size_t git_mwindow__file_limit;
43 extern size_t git_indexer__max_objects;
44 extern bool git_disable_pack_keep_file_checks;
45 extern int git_odb__packed_priority;
46 extern int git_odb__loose_priority;
47 
48 char *git__user_agent;
49 char *git__ssl_ciphers;
50 
libgit2_settings_global_shutdown(void)51 static void libgit2_settings_global_shutdown(void)
52 {
53 	git__free(git__user_agent);
54 	git__free(git__ssl_ciphers);
55 	git_repository__free_extensions();
56 }
57 
git_libgit2_settings_global_init(void)58 static int git_libgit2_settings_global_init(void)
59 {
60 	return git_runtime_shutdown_register(libgit2_settings_global_shutdown);
61 }
62 
git_libgit2_init(void)63 int git_libgit2_init(void)
64 {
65 	static git_runtime_init_fn init_fns[] = {
66 #ifdef GIT_WIN32
67 		git_win32_leakcheck_global_init,
68 #endif
69 		git_allocator_global_init,
70 		git_threadstate_global_init,
71 		git_threads_global_init,
72 		git_hash_global_init,
73 		git_sysdir_global_init,
74 		git_filter_global_init,
75 		git_merge_driver_global_init,
76 		git_transport_ssh_global_init,
77 		git_stream_registry_global_init,
78 		git_openssl_stream_global_init,
79 		git_mbedtls_stream_global_init,
80 		git_mwindow_global_init,
81 		git_pool_global_init,
82 		git_libgit2_settings_global_init
83 	};
84 
85 	return git_runtime_init(init_fns, ARRAY_SIZE(init_fns));
86 }
87 
git_libgit2_init_count(void)88 int git_libgit2_init_count(void)
89 {
90 	return git_runtime_init_count();
91 }
92 
git_libgit2_shutdown(void)93 int git_libgit2_shutdown(void)
94 {
95 	return git_runtime_shutdown();
96 }
97 
git_libgit2_version(int * major,int * minor,int * rev)98 int git_libgit2_version(int *major, int *minor, int *rev)
99 {
100 	*major = LIBGIT2_VER_MAJOR;
101 	*minor = LIBGIT2_VER_MINOR;
102 	*rev = LIBGIT2_VER_REVISION;
103 
104 	return 0;
105 }
106 
git_libgit2_features(void)107 int git_libgit2_features(void)
108 {
109 	return 0
110 #ifdef GIT_THREADS
111 		| GIT_FEATURE_THREADS
112 #endif
113 #ifdef GIT_HTTPS
114 		| GIT_FEATURE_HTTPS
115 #endif
116 #if defined(GIT_SSH)
117 		| GIT_FEATURE_SSH
118 #endif
119 #if defined(GIT_USE_NSEC)
120 		| GIT_FEATURE_NSEC
121 #endif
122 	;
123 }
124 
config_level_to_sysdir(int * out,int config_level)125 static int config_level_to_sysdir(int *out, int config_level)
126 {
127 	switch (config_level) {
128 	case GIT_CONFIG_LEVEL_SYSTEM:
129 		*out = GIT_SYSDIR_SYSTEM;
130 		return 0;
131 	case GIT_CONFIG_LEVEL_XDG:
132 		*out = GIT_SYSDIR_XDG;
133 		return 0;
134 	case GIT_CONFIG_LEVEL_GLOBAL:
135 		*out = GIT_SYSDIR_GLOBAL;
136 		return 0;
137 	case GIT_CONFIG_LEVEL_PROGRAMDATA:
138 		*out = GIT_SYSDIR_PROGRAMDATA;
139 		return 0;
140 	default:
141 		break;
142 	}
143 
144 	git_error_set(
145 		GIT_ERROR_INVALID, "invalid config path selector %d", config_level);
146 	return -1;
147 }
148 
git_libgit2__user_agent(void)149 const char *git_libgit2__user_agent(void)
150 {
151 	return git__user_agent;
152 }
153 
git_libgit2__ssl_ciphers(void)154 const char *git_libgit2__ssl_ciphers(void)
155 {
156 	return git__ssl_ciphers;
157 }
158 
git_libgit2_opts(int key,...)159 int git_libgit2_opts(int key, ...)
160 {
161 	int error = 0;
162 	va_list ap;
163 
164 	va_start(ap, key);
165 
166 	switch (key) {
167 	case GIT_OPT_SET_MWINDOW_SIZE:
168 		git_mwindow__window_size = va_arg(ap, size_t);
169 		break;
170 
171 	case GIT_OPT_GET_MWINDOW_SIZE:
172 		*(va_arg(ap, size_t *)) = git_mwindow__window_size;
173 		break;
174 
175 	case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
176 		git_mwindow__mapped_limit = va_arg(ap, size_t);
177 		break;
178 
179 	case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
180 		*(va_arg(ap, size_t *)) = git_mwindow__mapped_limit;
181 		break;
182 
183 	case GIT_OPT_SET_MWINDOW_FILE_LIMIT:
184 		git_mwindow__file_limit = va_arg(ap, size_t);
185 		break;
186 
187 	case GIT_OPT_GET_MWINDOW_FILE_LIMIT:
188 		*(va_arg(ap, size_t *)) = git_mwindow__file_limit;
189 		break;
190 
191 	case GIT_OPT_GET_SEARCH_PATH:
192 		{
193 			int sysdir = va_arg(ap, int);
194 			git_buf *out = va_arg(ap, git_buf *);
195 			const git_buf *tmp;
196 			int level;
197 
198 			if ((error = config_level_to_sysdir(&level, sysdir)) < 0 ||
199 			    (error = git_buf_sanitize(out)) < 0 ||
200 			    (error = git_sysdir_get(&tmp, level)) < 0)
201 				break;
202 
203 			error = git_buf_sets(out, tmp->ptr);
204 		}
205 		break;
206 
207 	case GIT_OPT_SET_SEARCH_PATH:
208 		{
209 			int level;
210 
211 			if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0)
212 				error = git_sysdir_set(level, va_arg(ap, const char *));
213 		}
214 		break;
215 
216 	case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
217 		{
218 			git_object_t type = (git_object_t)va_arg(ap, int);
219 			size_t size = va_arg(ap, size_t);
220 			error = git_cache_set_max_object_size(type, size);
221 			break;
222 		}
223 
224 	case GIT_OPT_SET_CACHE_MAX_SIZE:
225 		git_cache__max_storage = va_arg(ap, ssize_t);
226 		break;
227 
228 	case GIT_OPT_ENABLE_CACHING:
229 		git_cache__enabled = (va_arg(ap, int) != 0);
230 		break;
231 
232 	case GIT_OPT_GET_CACHED_MEMORY:
233 		*(va_arg(ap, ssize_t *)) = git_cache__current_storage.val;
234 		*(va_arg(ap, ssize_t *)) = git_cache__max_storage;
235 		break;
236 
237 	case GIT_OPT_GET_TEMPLATE_PATH:
238 		{
239 			git_buf *out = va_arg(ap, git_buf *);
240 			const git_buf *tmp;
241 
242 			if ((error = git_buf_sanitize(out)) < 0 ||
243 			    (error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0)
244 				break;
245 
246 			error = git_buf_sets(out, tmp->ptr);
247 		}
248 		break;
249 
250 	case GIT_OPT_SET_TEMPLATE_PATH:
251 		error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *));
252 		break;
253 
254 	case GIT_OPT_SET_SSL_CERT_LOCATIONS:
255 #ifdef GIT_OPENSSL
256 		{
257 			const char *file = va_arg(ap, const char *);
258 			const char *path = va_arg(ap, const char *);
259 			error = git_openssl__set_cert_location(file, path);
260 		}
261 #elif defined(GIT_MBEDTLS)
262 		{
263 			const char *file = va_arg(ap, const char *);
264 			const char *path = va_arg(ap, const char *);
265 			error = git_mbedtls__set_cert_location(file, path);
266 		}
267 #else
268 		git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations");
269 		error = -1;
270 #endif
271 		break;
272 	case GIT_OPT_SET_USER_AGENT:
273 		git__free(git__user_agent);
274 		git__user_agent = git__strdup(va_arg(ap, const char *));
275 		if (!git__user_agent) {
276 			git_error_set_oom();
277 			error = -1;
278 		}
279 
280 		break;
281 
282 	case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION:
283 		git_object__strict_input_validation = (va_arg(ap, int) != 0);
284 		break;
285 
286 	case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
287 		git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
288 		break;
289 
290 	case GIT_OPT_SET_SSL_CIPHERS:
291 #if (GIT_OPENSSL || GIT_MBEDTLS)
292 		{
293 			git__free(git__ssl_ciphers);
294 			git__ssl_ciphers = git__strdup(va_arg(ap, const char *));
295 			if (!git__ssl_ciphers) {
296 				git_error_set_oom();
297 				error = -1;
298 			}
299 		}
300 #else
301 		git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers");
302 		error = -1;
303 #endif
304 		break;
305 
306 	case GIT_OPT_GET_USER_AGENT:
307 		{
308 			git_buf *out = va_arg(ap, git_buf *);
309 			if ((error = git_buf_sanitize(out)) < 0)
310 				break;
311 			error = git_buf_sets(out, git__user_agent);
312 		}
313 		break;
314 
315 	case GIT_OPT_ENABLE_OFS_DELTA:
316 		git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0);
317 		break;
318 
319 	case GIT_OPT_ENABLE_FSYNC_GITDIR:
320 		git_repository__fsync_gitdir = (va_arg(ap, int) != 0);
321 		break;
322 
323 	case GIT_OPT_GET_WINDOWS_SHAREMODE:
324 #ifdef GIT_WIN32
325 		*(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
326 #endif
327 		break;
328 
329 	case GIT_OPT_SET_WINDOWS_SHAREMODE:
330 #ifdef GIT_WIN32
331 		git_win32__createfile_sharemode = va_arg(ap, unsigned long);
332 #endif
333 		break;
334 
335 	case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
336 		git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
337 		break;
338 
339 	case GIT_OPT_SET_ALLOCATOR:
340 		error = git_allocator_setup(va_arg(ap, git_allocator *));
341 		break;
342 
343 	case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY:
344 		git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
345 		break;
346 
347 	case GIT_OPT_SET_PACK_MAX_OBJECTS:
348 		git_indexer__max_objects = va_arg(ap, size_t);
349 		break;
350 
351 	case GIT_OPT_GET_PACK_MAX_OBJECTS:
352 		*(va_arg(ap, size_t *)) = git_indexer__max_objects;
353 		break;
354 
355 	case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS:
356 		git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0);
357 		break;
358 
359 	case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE:
360 		git_http__expect_continue = (va_arg(ap, int) != 0);
361 		break;
362 
363 	case GIT_OPT_SET_ODB_PACKED_PRIORITY:
364 		git_odb__packed_priority = va_arg(ap, int);
365 		break;
366 
367 	case GIT_OPT_SET_ODB_LOOSE_PRIORITY:
368 		git_odb__loose_priority = va_arg(ap, int);
369 		break;
370 
371 	case GIT_OPT_SET_EXTENSIONS:
372 		{
373 			const char **extensions = va_arg(ap, const char **);
374 			size_t len = va_arg(ap, size_t);
375 			error = git_repository__set_extensions(extensions, len);
376 		}
377 		break;
378 
379 	case GIT_OPT_GET_EXTENSIONS:
380 		{
381 			git_strarray *out = va_arg(ap, git_strarray *);
382 			char **extensions;
383 			size_t len;
384 
385 			if ((error = git_repository__extensions(&extensions, &len)) < 0)
386 				break;
387 
388 			out->strings = extensions;
389 			out->count = len;
390 		}
391 		break;
392 
393 	default:
394 		git_error_set(GIT_ERROR_INVALID, "invalid option key");
395 		error = -1;
396 	}
397 
398 	va_end(ap);
399 
400 	return error;
401 }
402