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