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}