git2/opts.rs
1//! Bindings to libgit2's git_libgit2_opts function.
2
3use std::ffi::CString;
4use std::ptr;
5
6use crate::string_array::StringArray;
7use crate::util::Binding;
8use crate::{raw, Buf, ConfigLevel, Error, IntoCString, ObjectType};
9
10/// Set the search path for a level of config data. The search path applied to
11/// shared attributes and ignore files, too.
12///
13/// `level` must be one of [`ConfigLevel::System`], [`ConfigLevel::Global`],
14/// [`ConfigLevel::XDG`], [`ConfigLevel::ProgramData`].
15///
16/// `path` lists directories delimited by `GIT_PATH_LIST_SEPARATOR`.
17/// Use magic path `$PATH` to include the old value of the path
18/// (if you want to prepend or append, for instance).
19///
20/// This function is unsafe as it mutates the global state but cannot guarantee
21/// thread-safety. It needs to be externally synchronized with calls to access
22/// the global state.
23pub unsafe fn set_search_path<P>(level: ConfigLevel, path: P) -> Result<(), Error>
24where
25 P: IntoCString,
26{
27 crate::init();
28 try_call!(raw::git_libgit2_opts(
29 raw::GIT_OPT_SET_SEARCH_PATH as libc::c_int,
30 level as libc::c_int,
31 path.into_c_string()?.as_ptr()
32 ));
33 Ok(())
34}
35
36/// Reset the search path for a given level of config data to the default
37/// (generally based on environment variables).
38///
39/// `level` must be one of [`ConfigLevel::System`], [`ConfigLevel::Global`],
40/// [`ConfigLevel::XDG`], [`ConfigLevel::ProgramData`].
41///
42/// This function is unsafe as it mutates the global state but cannot guarantee
43/// thread-safety. It needs to be externally synchronized with calls to access
44/// the global state.
45pub unsafe fn reset_search_path(level: ConfigLevel) -> Result<(), Error> {
46 crate::init();
47 try_call!(raw::git_libgit2_opts(
48 raw::GIT_OPT_SET_SEARCH_PATH as libc::c_int,
49 level as libc::c_int,
50 core::ptr::null::<u8>()
51 ));
52 Ok(())
53}
54
55/// Get the search path for a given level of config data.
56///
57/// `level` must be one of [`ConfigLevel::System`], [`ConfigLevel::Global`],
58/// [`ConfigLevel::XDG`], [`ConfigLevel::ProgramData`].
59///
60/// This function is unsafe as it mutates the global state but cannot guarantee
61/// thread-safety. It needs to be externally synchronized with calls to access
62/// the global state.
63pub unsafe fn get_search_path(level: ConfigLevel) -> Result<CString, Error> {
64 crate::init();
65 let buf = Buf::new();
66 try_call!(raw::git_libgit2_opts(
67 raw::GIT_OPT_GET_SEARCH_PATH as libc::c_int,
68 level as libc::c_int,
69 buf.raw() as *const _
70 ));
71 buf.into_c_string()
72}
73
74/// Controls whether or not libgit2 will cache loaded objects. Enabled by
75/// default, but disabling this can improve performance and memory usage if
76/// loading a large number of objects that will not be referenced again.
77/// Disabling this will cause repository objects to clear their caches when next
78/// accessed.
79pub fn enable_caching(enabled: bool) {
80 crate::init();
81 let error = unsafe {
82 raw::git_libgit2_opts(
83 raw::GIT_OPT_ENABLE_CACHING as libc::c_int,
84 enabled as libc::c_int,
85 )
86 };
87 // This function cannot actually fail, but the function has an error return
88 // for other options that can.
89 debug_assert!(error >= 0);
90}
91
92/// Set the maximum data size for the given type of object to be considered
93/// eligible for caching in memory. Setting to value to zero means that that
94/// type of object will not be cached. Defaults to 0 for [`ObjectType::Blob`]
95/// (i.e. won't cache blobs) and 4k for [`ObjectType::Commit`],
96/// [`ObjectType::Tree`], and [`ObjectType::Tag`].
97///
98/// `kind` must be one of [`ObjectType::Blob`], [`ObjectType::Commit`],
99/// [`ObjectType::Tree`], and [`ObjectType::Tag`].
100///
101/// # Safety
102/// This function is modifying a C global without synchronization, so it is not
103/// thread safe, and should only be called before any thread is spawned.
104pub unsafe fn set_cache_object_limit(kind: ObjectType, size: libc::size_t) -> Result<(), Error> {
105 crate::init();
106 try_call!(raw::git_libgit2_opts(
107 raw::GIT_OPT_SET_CACHE_OBJECT_LIMIT as libc::c_int,
108 kind as libc::c_int,
109 size
110 ));
111 Ok(())
112}
113
114/// Controls whether or not libgit2 will verify when writing an object that all
115/// objects it references are valid. Enabled by default, but disabling this can
116/// significantly improve performance, at the cost of potentially allowing the
117/// creation of objects that reference invalid objects (due to programming
118/// error or repository corruption).
119pub fn strict_object_creation(enabled: bool) {
120 crate::init();
121 let error = unsafe {
122 raw::git_libgit2_opts(
123 raw::GIT_OPT_ENABLE_STRICT_OBJECT_CREATION as libc::c_int,
124 enabled as libc::c_int,
125 )
126 };
127 // This function cannot actually fail, but the function has an error return
128 // for other options that can.
129 debug_assert!(error >= 0);
130}
131
132/// Controls whether or not libgit2 will verify that objects loaded have the
133/// expected hash. Enabled by default, but disabling this can significantly
134/// improve performance, at the cost of relying on repository integrity
135/// without checking it.
136pub fn strict_hash_verification(enabled: bool) {
137 crate::init();
138 let error = unsafe {
139 raw::git_libgit2_opts(
140 raw::GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION as libc::c_int,
141 enabled as libc::c_int,
142 )
143 };
144 // This function cannot actually fail, but the function has an error return
145 // for other options that can.
146 debug_assert!(error >= 0);
147}
148
149/// Returns the list of git extensions that are supported. This is the list of
150/// built-in extensions supported by libgit2 and custom extensions that have
151/// been added with [`set_extensions`]. Extensions that have been negated will
152/// not be returned.
153///
154/// # Safety
155///
156/// libgit2 stores user extensions in a static variable.
157/// This function is effectively reading a `static mut` and should be treated as such
158pub unsafe fn get_extensions() -> Result<StringArray, Error> {
159 crate::init();
160
161 let mut extensions = raw::git_strarray {
162 strings: ptr::null_mut(),
163 count: 0,
164 };
165
166 try_call!(raw::git_libgit2_opts(
167 raw::GIT_OPT_GET_EXTENSIONS as libc::c_int,
168 &mut extensions
169 ));
170
171 Ok(StringArray::from_raw(extensions))
172}
173
174/// Set that the given git extensions are supported by the caller. Extensions
175/// supported by libgit2 may be negated by prefixing them with a `!`.
176/// For example: setting extensions to `[ "!noop", "newext" ]` indicates that
177/// the caller does not want to support repositories with the `noop` extension
178/// but does want to support repositories with the `newext` extension.
179///
180/// # Safety
181///
182/// libgit2 stores user extensions in a static variable.
183/// This function is effectively modifying a `static mut` and should be treated as such
184pub unsafe fn set_extensions<E>(extensions: &[E]) -> Result<(), Error>
185where
186 for<'x> &'x E: IntoCString,
187{
188 crate::init();
189
190 let extensions = extensions
191 .iter()
192 .map(|e| e.into_c_string())
193 .collect::<Result<Vec<_>, _>>()?;
194
195 let extension_ptrs = extensions.iter().map(|e| e.as_ptr()).collect::<Vec<_>>();
196
197 try_call!(raw::git_libgit2_opts(
198 raw::GIT_OPT_SET_EXTENSIONS as libc::c_int,
199 extension_ptrs.as_ptr(),
200 extension_ptrs.len() as libc::size_t
201 ));
202
203 Ok(())
204}
205
206/// Set whether or not to verify ownership before performing a repository.
207/// Enabled by default, but disabling this can lead to code execution vulnerabilities.
208pub unsafe fn set_verify_owner_validation(enabled: bool) -> Result<(), Error> {
209 crate::init();
210 let error = raw::git_libgit2_opts(
211 raw::GIT_OPT_SET_OWNER_VALIDATION as libc::c_int,
212 enabled as libc::c_int,
213 );
214 // This function cannot actually fail, but the function has an error return
215 // for other options that can.
216 debug_assert!(error >= 0);
217 Ok(())
218}
219
220/// Set the SSL certificate-authority location to `file`. `file` is the location
221/// of a file containing several certificates concatenated together.
222pub unsafe fn set_ssl_cert_file<P>(file: P) -> Result<(), Error>
223where
224 P: IntoCString,
225{
226 crate::init();
227
228 unsafe {
229 try_call!(raw::git_libgit2_opts(
230 raw::GIT_OPT_SET_SSL_CERT_LOCATIONS as libc::c_int,
231 file.into_c_string()?.as_ptr(),
232 core::ptr::null::<libc::c_char>()
233 ));
234 }
235
236 Ok(())
237}
238
239/// Set the SSL certificate-authority location to `path`. `path` is the location
240/// of a directory holding several certificates, one per file.
241pub unsafe fn set_ssl_cert_dir<P>(path: P) -> Result<(), Error>
242where
243 P: IntoCString,
244{
245 crate::init();
246
247 unsafe {
248 try_call!(raw::git_libgit2_opts(
249 raw::GIT_OPT_SET_SSL_CERT_LOCATIONS as libc::c_int,
250 core::ptr::null::<libc::c_char>(),
251 path.into_c_string()?.as_ptr()
252 ));
253 }
254
255 Ok(())
256}
257
258/// Get the maximum mmap window size
259///
260/// # Safety
261/// This function is reading a C global without synchronization, so it is not
262/// thread safe, and should only be called before any thread is spawned.
263pub unsafe fn get_mwindow_size() -> Result<libc::size_t, Error> {
264 crate::init();
265
266 let mut size = 0;
267
268 try_call!(raw::git_libgit2_opts(
269 raw::GIT_OPT_GET_MWINDOW_SIZE as libc::c_int,
270 &mut size
271 ));
272
273 Ok(size)
274}
275
276/// Set the maximum mmap window size
277///
278/// # Safety
279/// This function is modifying a C global without synchronization, so it is not
280/// thread safe, and should only be called before any thread is spawned.
281pub unsafe fn set_mwindow_size(size: libc::size_t) -> Result<(), Error> {
282 crate::init();
283
284 try_call!(raw::git_libgit2_opts(
285 raw::GIT_OPT_SET_MWINDOW_SIZE as libc::c_int,
286 size
287 ));
288
289 Ok(())
290}
291
292/// Get the maximum memory that will be mapped in total by the library
293///
294/// # Safety
295/// This function is reading a C global without synchronization, so it is not
296/// thread safe, and should only be called before any thread is spawned.
297pub unsafe fn get_mwindow_mapped_limit() -> Result<libc::size_t, Error> {
298 crate::init();
299
300 let mut limit = 0;
301
302 try_call!(raw::git_libgit2_opts(
303 raw::GIT_OPT_GET_MWINDOW_MAPPED_LIMIT as libc::c_int,
304 &mut limit
305 ));
306
307 Ok(limit)
308}
309
310/// Set the maximum amount of memory that can be mapped at any time
311/// by the library.
312///
313/// # Safety
314/// This function is modifying a C global without synchronization, so it is not
315/// thread safe, and should only be called before any thread is spawned.
316pub unsafe fn set_mwindow_mapped_limit(limit: libc::size_t) -> Result<(), Error> {
317 crate::init();
318
319 try_call!(raw::git_libgit2_opts(
320 raw::GIT_OPT_SET_MWINDOW_MAPPED_LIMIT as libc::c_int,
321 limit
322 ));
323
324 Ok(())
325}
326
327/// Get the maximum number of files that will be mapped at any time by the
328/// library.
329///
330/// # Safety
331/// This function is reading a C global without synchronization, so it is not
332/// thread safe, and should only be called before any thread is spawned.
333pub unsafe fn get_mwindow_file_limit() -> Result<libc::size_t, Error> {
334 crate::init();
335
336 let mut limit = 0;
337
338 try_call!(raw::git_libgit2_opts(
339 raw::GIT_OPT_GET_MWINDOW_FILE_LIMIT as libc::c_int,
340 &mut limit
341 ));
342
343 Ok(limit)
344}
345
346/// Set the maximum number of files that can be mapped at any time
347/// by the library. The default (0) is unlimited.
348///
349/// # Safety
350/// This function is modifying a C global without synchronization, so it is not
351/// thread safe, and should only be called before any thread is spawned.
352pub unsafe fn set_mwindow_file_limit(limit: libc::size_t) -> Result<(), Error> {
353 crate::init();
354
355 try_call!(raw::git_libgit2_opts(
356 raw::GIT_OPT_SET_MWINDOW_FILE_LIMIT as libc::c_int,
357 limit
358 ));
359
360 Ok(())
361}
362
363/// Get server connect timeout in milliseconds
364///
365/// # Safety
366/// This function is modifying a C global without synchronization, so it is not
367/// thread safe, and should only be called before any thread is spawned.
368pub unsafe fn get_server_connect_timeout_in_milliseconds() -> Result<libc::c_int, Error> {
369 crate::init();
370
371 let mut server_connect_timeout = 0;
372
373 try_call!(raw::git_libgit2_opts(
374 raw::GIT_OPT_GET_SERVER_CONNECT_TIMEOUT as libc::c_int,
375 &mut server_connect_timeout
376 ));
377
378 Ok(server_connect_timeout)
379}
380
381/// Set server connect timeout in milliseconds
382///
383/// # Safety
384/// This function is modifying a C global without synchronization, so it is not
385/// thread safe, and should only be called before any thread is spawned.
386pub unsafe fn set_server_connect_timeout_in_milliseconds(
387 timeout: libc::c_int,
388) -> Result<(), Error> {
389 crate::init();
390
391 let error = raw::git_libgit2_opts(
392 raw::GIT_OPT_SET_SERVER_CONNECT_TIMEOUT as libc::c_int,
393 timeout,
394 );
395 // This function cannot actually fail, but the function has an error return
396 // for other options that can.
397 debug_assert!(error >= 0);
398
399 Ok(())
400}
401
402/// Get server timeout in milliseconds
403///
404/// # Safety
405/// This function is modifying a C global without synchronization, so it is not
406/// thread safe, and should only be called before any thread is spawned.
407pub unsafe fn get_server_timeout_in_milliseconds() -> Result<libc::c_int, Error> {
408 crate::init();
409
410 let mut server_timeout = 0;
411
412 try_call!(raw::git_libgit2_opts(
413 raw::GIT_OPT_GET_SERVER_TIMEOUT as libc::c_int,
414 &mut server_timeout
415 ));
416
417 Ok(server_timeout)
418}
419
420/// Set server timeout in milliseconds
421///
422/// # Safety
423/// This function is modifying a C global without synchronization, so it is not
424/// thread safe, and should only be called before any thread is spawned.
425pub unsafe fn set_server_timeout_in_milliseconds(timeout: libc::c_int) -> Result<(), Error> {
426 crate::init();
427
428 let error = raw::git_libgit2_opts(
429 raw::GIT_OPT_SET_SERVER_TIMEOUT as libc::c_int,
430 timeout as libc::c_int,
431 );
432 // This function cannot actually fail, but the function has an error return
433 // for other options that can.
434 debug_assert!(error >= 0);
435
436 Ok(())
437}
438
439#[cfg(test)]
440mod test {
441 use super::*;
442
443 #[test]
444 fn smoke() {
445 strict_hash_verification(false);
446 }
447
448 #[test]
449 fn mwindow_size() {
450 unsafe {
451 assert!(set_mwindow_size(1024).is_ok());
452 assert!(get_mwindow_size().unwrap() == 1024);
453 }
454 }
455
456 #[test]
457 fn mwindow_mapped_limit() {
458 unsafe {
459 assert!(set_mwindow_mapped_limit(1024).is_ok());
460 assert!(get_mwindow_mapped_limit().unwrap() == 1024);
461 }
462 }
463
464 #[test]
465 fn mwindow_file_limit() {
466 unsafe {
467 assert!(set_mwindow_file_limit(1024).is_ok());
468 assert!(get_mwindow_file_limit().unwrap() == 1024);
469 }
470 }
471
472 #[test]
473 fn server_connect_timeout() {
474 unsafe {
475 assert!(set_server_connect_timeout_in_milliseconds(5000).is_ok());
476 assert!(get_server_connect_timeout_in_milliseconds().unwrap() == 5000);
477 }
478 }
479
480 #[test]
481 fn server_timeout() {
482 unsafe {
483 assert!(set_server_timeout_in_milliseconds(10_000).is_ok());
484 assert!(get_server_timeout_in_milliseconds().unwrap() == 10_000);
485 }
486 }
487}