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.
10 #include "git2/config.h"
11 #include "git2/sys/config.h"
14 #include "config_backend.h"
17 #include "transaction.h"
25 void git_config_entry_free(git_config_entry
*entry
)
36 git_config_backend
*backend
;
37 git_config_level_t level
;
40 static void backend_internal_free(backend_internal
*internal
)
42 git_config_backend
*backend
;
44 backend
= internal
->backend
;
45 backend
->free(backend
);
49 static void config_free(git_config
*cfg
)
52 backend_internal
*internal
;
54 for (i
= 0; i
< cfg
->backends
.length
; ++i
) {
55 internal
= git_vector_get(&cfg
->backends
, i
);
56 GIT_REFCOUNT_DEC(internal
, backend_internal_free
);
59 git_vector_free(&cfg
->backends
);
61 git__memzero(cfg
, sizeof(*cfg
));
65 void git_config_free(git_config
*cfg
)
70 GIT_REFCOUNT_DEC(cfg
, config_free
);
73 static int config_backend_cmp(const void *a
, const void *b
)
75 const backend_internal
*bk_a
= (const backend_internal
*)(a
);
76 const backend_internal
*bk_b
= (const backend_internal
*)(b
);
78 return bk_b
->level
- bk_a
->level
;
81 int git_config_new(git_config
**out
)
85 cfg
= git__malloc(sizeof(git_config
));
86 GIT_ERROR_CHECK_ALLOC(cfg
);
88 memset(cfg
, 0x0, sizeof(git_config
));
90 if (git_vector_init(&cfg
->backends
, 3, config_backend_cmp
) < 0) {
96 GIT_REFCOUNT_INC(cfg
);
100 int git_config_add_file_ondisk(
103 git_config_level_t level
,
104 const git_repository
*repo
,
107 git_config_backend
*file
= NULL
;
112 GIT_ASSERT_ARG(path
);
114 res
= p_stat(path
, &st
);
115 if (res
< 0 && errno
!= ENOENT
&& errno
!= ENOTDIR
) {
116 git_error_set(GIT_ERROR_CONFIG
, "failed to stat '%s'", path
);
120 if (git_config_backend_from_file(&file
, path
) < 0)
123 if ((res
= git_config_add_backend(cfg
, file
, level
, repo
, force
)) < 0) {
125 * free manually; the file is not owned by the config
126 * instance yet and will not be freed on cleanup
135 int git_config_open_ondisk(git_config
**out
, const char *path
)
142 if (git_config_new(&config
) < 0)
145 if ((error
= git_config_add_file_ondisk(config
, path
, GIT_CONFIG_LEVEL_LOCAL
, NULL
, 0)) < 0)
146 git_config_free(config
);
153 int git_config_snapshot(git_config
**out
, git_config
*in
)
157 backend_internal
*internal
;
162 if (git_config_new(&config
) < 0)
165 git_vector_foreach(&in
->backends
, i
, internal
) {
166 git_config_backend
*b
;
168 if ((error
= internal
->backend
->snapshot(&b
, internal
->backend
)) < 0)
171 if ((error
= git_config_add_backend(config
, b
, internal
->level
, NULL
, 0)) < 0) {
178 git_config_free(config
);
185 static int find_backend_by_level(
186 backend_internal
**out
,
187 const git_config
*cfg
,
188 git_config_level_t level
)
191 backend_internal
*internal
;
194 /* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config backend
195 * which has the highest level. As config backends are stored in a vector
196 * sorted by decreasing order of level, getting the backend at position 0
199 if (level
== GIT_CONFIG_HIGHEST_LEVEL
) {
202 git_vector_foreach(&cfg
->backends
, i
, internal
) {
203 if (internal
->level
== level
)
209 git_error_set(GIT_ERROR_CONFIG
,
210 "no configuration exists for the given level '%i'", (int)level
);
211 return GIT_ENOTFOUND
;
214 *out
= git_vector_get(&cfg
->backends
, pos
);
219 static int duplicate_level(void **old_raw
, void *new_raw
)
221 backend_internal
**old
= (backend_internal
**)old_raw
;
225 git_error_set(GIT_ERROR_CONFIG
, "there already exists a configuration for the given level (%i)", (int)(*old
)->level
);
229 static void try_remove_existing_backend(
231 git_config_level_t level
)
234 backend_internal
*internal
;
237 git_vector_foreach(&cfg
->backends
, i
, internal
) {
238 if (internal
->level
== level
)
245 internal
= git_vector_get(&cfg
->backends
, pos
);
247 if (git_vector_remove(&cfg
->backends
, pos
) < 0)
250 GIT_REFCOUNT_DEC(internal
, backend_internal_free
);
253 static int git_config__add_internal(
255 backend_internal
*internal
,
256 git_config_level_t level
,
261 /* delete existing config backend for level if it exists */
263 try_remove_existing_backend(cfg
, level
);
265 if ((result
= git_vector_insert_sorted(&cfg
->backends
,
266 internal
, &duplicate_level
)) < 0)
269 git_vector_sort(&cfg
->backends
);
270 internal
->backend
->cfg
= cfg
;
272 GIT_REFCOUNT_INC(internal
);
277 int git_config_open_global(git_config
**cfg_out
, git_config
*cfg
)
279 if (!git_config_open_level(cfg_out
, cfg
, GIT_CONFIG_LEVEL_XDG
))
282 return git_config_open_level(cfg_out
, cfg
, GIT_CONFIG_LEVEL_GLOBAL
);
285 int git_config_open_level(
286 git_config
**cfg_out
,
287 const git_config
*cfg_parent
,
288 git_config_level_t level
)
291 backend_internal
*internal
;
294 if ((res
= find_backend_by_level(&internal
, cfg_parent
, level
)) < 0)
297 if ((res
= git_config_new(&cfg
)) < 0)
300 if ((res
= git_config__add_internal(cfg
, internal
, level
, true)) < 0) {
301 git_config_free(cfg
);
310 int git_config_add_backend(
312 git_config_backend
*backend
,
313 git_config_level_t level
,
314 const git_repository
*repo
,
317 backend_internal
*internal
;
321 GIT_ASSERT_ARG(backend
);
323 GIT_ERROR_CHECK_VERSION(backend
, GIT_CONFIG_BACKEND_VERSION
, "git_config_backend");
325 if ((result
= backend
->open(backend
, level
, repo
)) < 0)
328 internal
= git__malloc(sizeof(backend_internal
));
329 GIT_ERROR_CHECK_ALLOC(internal
);
331 memset(internal
, 0x0, sizeof(backend_internal
));
333 internal
->backend
= backend
;
334 internal
->level
= level
;
336 if ((result
= git_config__add_internal(cfg
, internal
, level
, force
)) < 0) {
345 * Loop over all the variables
349 git_config_iterator parent
;
350 git_config_iterator
*current
;
351 const git_config
*cfg
;
356 static int find_next_backend(size_t *out
, const git_config
*cfg
, size_t i
)
358 backend_internal
*internal
;
361 internal
= git_vector_get(&cfg
->backends
, i
- 1);
362 if (!internal
|| !internal
->backend
)
372 static int all_iter_next(git_config_entry
**entry
, git_config_iterator
*_iter
)
374 all_iter
*iter
= (all_iter
*) _iter
;
375 backend_internal
*internal
;
376 git_config_backend
*backend
;
380 if (iter
->current
!= NULL
&&
381 (error
= iter
->current
->next(entry
, iter
->current
)) == 0) {
385 if (error
< 0 && error
!= GIT_ITEROVER
)
389 if (find_next_backend(&i
, iter
->cfg
, iter
->i
) < 0)
392 internal
= git_vector_get(&iter
->cfg
->backends
, i
- 1);
393 backend
= internal
->backend
;
397 iter
->current
->free(iter
->current
);
399 iter
->current
= NULL
;
400 error
= backend
->iterator(&iter
->current
, backend
);
401 if (error
== GIT_ENOTFOUND
)
407 error
= iter
->current
->next(entry
, iter
->current
);
408 /* If this backend is empty, then keep going */
409 if (error
== GIT_ITEROVER
)
419 static int all_iter_glob_next(git_config_entry
**entry
, git_config_iterator
*_iter
)
422 all_iter
*iter
= (all_iter
*) _iter
;
425 * We use the "normal" function to grab the next one across
426 * backends and then apply the regex
428 while ((error
= all_iter_next(entry
, _iter
)) == 0) {
429 /* skip non-matching keys if regexp was provided */
430 if (git_regexp_match(&iter
->regex
, (*entry
)->name
) != 0)
433 /* and simply return if we like the entry's name */
440 static void all_iter_free(git_config_iterator
*_iter
)
442 all_iter
*iter
= (all_iter
*) _iter
;
445 iter
->current
->free(iter
->current
);
450 static void all_iter_glob_free(git_config_iterator
*_iter
)
452 all_iter
*iter
= (all_iter
*) _iter
;
454 git_regexp_dispose(&iter
->regex
);
455 all_iter_free(_iter
);
458 int git_config_iterator_new(git_config_iterator
**out
, const git_config
*cfg
)
462 iter
= git__calloc(1, sizeof(all_iter
));
463 GIT_ERROR_CHECK_ALLOC(iter
);
465 iter
->parent
.free
= all_iter_free
;
466 iter
->parent
.next
= all_iter_next
;
468 iter
->i
= cfg
->backends
.length
;
471 *out
= (git_config_iterator
*) iter
;
476 int git_config_iterator_glob_new(git_config_iterator
**out
, const git_config
*cfg
, const char *regexp
)
482 return git_config_iterator_new(out
, cfg
);
484 iter
= git__calloc(1, sizeof(all_iter
));
485 GIT_ERROR_CHECK_ALLOC(iter
);
487 if ((result
= git_regexp_compile(&iter
->regex
, regexp
, 0)) < 0) {
492 iter
->parent
.next
= all_iter_glob_next
;
493 iter
->parent
.free
= all_iter_glob_free
;
494 iter
->i
= cfg
->backends
.length
;
497 *out
= (git_config_iterator
*) iter
;
502 int git_config_foreach(
503 const git_config
*cfg
, git_config_foreach_cb cb
, void *payload
)
505 return git_config_foreach_match(cfg
, NULL
, cb
, payload
);
508 int git_config_backend_foreach_match(
509 git_config_backend
*backend
,
511 git_config_foreach_cb cb
,
514 git_config_entry
*entry
;
515 git_config_iterator
*iter
;
519 GIT_ASSERT_ARG(backend
);
522 if (regexp
&& git_regexp_compile(®ex
, regexp
, 0) < 0)
525 if ((error
= backend
->iterator(&iter
, backend
)) < 0) {
530 while (!(iter
->next(&entry
, iter
) < 0)) {
531 /* skip non-matching keys if regexp was provided */
532 if (regexp
&& git_regexp_match(®ex
, entry
->name
) != 0)
535 /* abort iterator on non-zero return value */
536 if ((error
= cb(entry
, payload
)) != 0) {
537 git_error_set_after_callback(error
);
543 git_regexp_dispose(®ex
);
550 int git_config_foreach_match(
551 const git_config
*cfg
,
553 git_config_foreach_cb cb
,
557 git_config_iterator
*iter
;
558 git_config_entry
*entry
;
560 if ((error
= git_config_iterator_glob_new(&iter
, cfg
, regexp
)) < 0)
563 while (!(error
= git_config_next(&entry
, iter
))) {
564 if ((error
= cb(entry
, payload
)) != 0) {
565 git_error_set_after_callback(error
);
570 git_config_iterator_free(iter
);
572 if (error
== GIT_ITEROVER
)
587 static const char *uses
[] = {
592 static int get_backend_for_use(git_config_backend
**out
,
593 git_config
*cfg
, const char *name
, backend_use use
)
596 backend_internal
*backend
;
600 if (git_vector_length(&cfg
->backends
) == 0) {
601 git_error_set(GIT_ERROR_CONFIG
,
602 "cannot %s value for '%s' when no config backends exist",
604 return GIT_ENOTFOUND
;
607 git_vector_foreach(&cfg
->backends
, i
, backend
) {
608 if (!backend
->backend
->readonly
) {
609 *out
= backend
->backend
;
614 git_error_set(GIT_ERROR_CONFIG
,
615 "cannot %s value for '%s' when all config backends are readonly",
617 return GIT_ENOTFOUND
;
620 int git_config_delete_entry(git_config
*cfg
, const char *name
)
622 git_config_backend
*backend
;
624 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_DELETE
) < 0)
625 return GIT_ENOTFOUND
;
627 return backend
->del(backend
, name
);
630 int git_config_set_int64(git_config
*cfg
, const char *name
, int64_t value
)
632 char str_value
[32]; /* All numbers should fit in here */
633 p_snprintf(str_value
, sizeof(str_value
), "%" PRId64
, value
);
634 return git_config_set_string(cfg
, name
, str_value
);
637 int git_config_set_int32(git_config
*cfg
, const char *name
, int32_t value
)
639 return git_config_set_int64(cfg
, name
, (int64_t)value
);
642 int git_config_set_bool(git_config
*cfg
, const char *name
, int value
)
644 return git_config_set_string(cfg
, name
, value
? "true" : "false");
647 int git_config_set_string(git_config
*cfg
, const char *name
, const char *value
)
650 git_config_backend
*backend
;
653 git_error_set(GIT_ERROR_CONFIG
, "the value to set cannot be NULL");
657 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_SET
) < 0)
658 return GIT_ENOTFOUND
;
660 error
= backend
->set(backend
, name
, value
);
662 if (!error
&& GIT_REFCOUNT_OWNER(cfg
) != NULL
)
663 git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(cfg
));
668 int git_config__update_entry(
672 bool overwrite_existing
,
673 bool only_if_existing
)
676 git_config_entry
*ce
= NULL
;
678 if ((error
= git_config__lookup_entry(&ce
, config
, key
, false)) < 0)
681 if (!ce
&& only_if_existing
) /* entry doesn't exist */
683 if (ce
&& !overwrite_existing
) /* entry would be overwritten */
685 if (value
&& ce
&& ce
->value
&& !strcmp(ce
->value
, value
)) /* no change */
687 if (!value
&& (!ce
|| !ce
->value
)) /* asked to delete absent entry */
691 error
= git_config_delete_entry(config
, key
);
693 error
= git_config_set_string(config
, key
, value
);
695 git_config_entry_free(ce
);
703 static int config_error_notfound(const char *name
)
705 git_error_set(GIT_ERROR_CONFIG
, "config value '%s' was not found", name
);
706 return GIT_ENOTFOUND
;
715 static int get_entry(
716 git_config_entry
**out
,
717 const git_config
*cfg
,
722 int res
= GIT_ENOTFOUND
;
723 const char *key
= name
;
724 char *normalized
= NULL
;
726 backend_internal
*internal
;
730 if (normalize_name
) {
731 if ((res
= git_config__normalize_name(name
, &normalized
)) < 0)
737 git_vector_foreach(&cfg
->backends
, i
, internal
) {
738 if (!internal
|| !internal
->backend
)
741 res
= internal
->backend
->get(internal
->backend
, key
, out
);
742 if (res
!= GIT_ENOTFOUND
)
746 git__free(normalized
);
749 if (res
== GIT_ENOTFOUND
)
750 res
= (want_errors
> GET_ALL_ERRORS
) ? 0 : config_error_notfound(name
);
751 else if (res
&& (want_errors
== GET_NO_ERRORS
)) {
759 int git_config_get_entry(
760 git_config_entry
**out
, const git_config
*cfg
, const char *name
)
762 return get_entry(out
, cfg
, name
, true, GET_ALL_ERRORS
);
765 int git_config__lookup_entry(
766 git_config_entry
**out
,
767 const git_config
*cfg
,
772 out
, cfg
, key
, false, no_errors
? GET_NO_ERRORS
: GET_NO_MISSING
);
775 int git_config_get_mapped(
777 const git_config
*cfg
,
779 const git_configmap
*maps
,
782 git_config_entry
*entry
;
785 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
788 ret
= git_config_lookup_map_value(out
, maps
, map_n
, entry
->value
);
789 git_config_entry_free(entry
);
794 int git_config_get_int64(int64_t *out
, const git_config
*cfg
, const char *name
)
796 git_config_entry
*entry
;
799 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
802 ret
= git_config_parse_int64(out
, entry
->value
);
803 git_config_entry_free(entry
);
808 int git_config_get_int32(int32_t *out
, const git_config
*cfg
, const char *name
)
810 git_config_entry
*entry
;
813 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
816 ret
= git_config_parse_int32(out
, entry
->value
);
817 git_config_entry_free(entry
);
822 int git_config_get_bool(int *out
, const git_config
*cfg
, const char *name
)
824 git_config_entry
*entry
;
827 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
830 ret
= git_config_parse_bool(out
, entry
->value
);
831 git_config_entry_free(entry
);
836 static int is_readonly(const git_config
*cfg
)
839 backend_internal
*internal
;
841 git_vector_foreach(&cfg
->backends
, i
, internal
) {
842 if (!internal
|| !internal
->backend
)
845 if (!internal
->backend
->readonly
)
852 static int git_config__parse_path(git_str
*out
, const char *value
)
855 GIT_ASSERT_ARG(value
);
857 if (value
[0] == '~') {
858 if (value
[1] != '\0' && value
[1] != '/') {
859 git_error_set(GIT_ERROR_CONFIG
, "retrieving a homedir by name is not supported");
863 return git_sysdir_expand_global_file(out
, value
[1] ? &value
[2] : NULL
);
866 return git_str_sets(out
, value
);
869 int git_config_parse_path(git_buf
*out
, const char *value
)
871 GIT_BUF_WRAP_PRIVATE(out
, git_config__parse_path
, value
);
874 int git_config_get_path(
876 const git_config
*cfg
,
879 GIT_BUF_WRAP_PRIVATE(out
, git_config__get_path
, cfg
, name
);
882 int git_config__get_path(
884 const git_config
*cfg
,
887 git_config_entry
*entry
;
890 if ((error
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
893 error
= git_config__parse_path(out
, entry
->value
);
894 git_config_entry_free(entry
);
899 int git_config_get_string(
900 const char **out
, const git_config
*cfg
, const char *name
)
902 git_config_entry
*entry
;
905 if (!is_readonly(cfg
)) {
906 git_error_set(GIT_ERROR_CONFIG
, "get_string called on a live config object");
910 ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
);
911 *out
= !ret
? (entry
->value
? entry
->value
: "") : NULL
;
913 git_config_entry_free(entry
);
918 int git_config_get_string_buf(
919 git_buf
*out
, const git_config
*cfg
, const char *name
)
921 GIT_BUF_WRAP_PRIVATE(out
, git_config__get_string_buf
, cfg
, name
);
924 int git_config__get_string_buf(
925 git_str
*out
, const git_config
*cfg
, const char *name
)
927 git_config_entry
*entry
;
934 ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
);
935 str
= !ret
? (entry
->value
? entry
->value
: "") : NULL
;
938 ret
= git_str_puts(out
, str
);
940 git_config_entry_free(entry
);
945 char *git_config__get_string_force(
946 const git_config
*cfg
, const char *key
, const char *fallback_value
)
948 git_config_entry
*entry
;
951 get_entry(&entry
, cfg
, key
, false, GET_NO_ERRORS
);
952 ret
= (entry
&& entry
->value
) ? git__strdup(entry
->value
) : fallback_value
? git__strdup(fallback_value
) : NULL
;
953 git_config_entry_free(entry
);
958 int git_config__get_bool_force(
959 const git_config
*cfg
, const char *key
, int fallback_value
)
961 int val
= fallback_value
;
962 git_config_entry
*entry
;
964 get_entry(&entry
, cfg
, key
, false, GET_NO_ERRORS
);
966 if (entry
&& git_config_parse_bool(&val
, entry
->value
) < 0)
969 git_config_entry_free(entry
);
973 int git_config__get_int_force(
974 const git_config
*cfg
, const char *key
, int fallback_value
)
976 int32_t val
= (int32_t)fallback_value
;
977 git_config_entry
*entry
;
979 get_entry(&entry
, cfg
, key
, false, GET_NO_ERRORS
);
981 if (entry
&& git_config_parse_int32(&val
, entry
->value
) < 0)
984 git_config_entry_free(entry
);
988 int git_config_get_multivar_foreach(
989 const git_config
*cfg
, const char *name
, const char *regexp
,
990 git_config_foreach_cb cb
, void *payload
)
993 git_config_iterator
*iter
;
994 git_config_entry
*entry
;
996 if ((err
= git_config_multivar_iterator_new(&iter
, cfg
, name
, regexp
)) < 0)
1000 while ((err
= iter
->next(&entry
, iter
)) == 0) {
1003 if ((err
= cb(entry
, payload
)) != 0) {
1004 git_error_set_after_callback(err
);
1010 if (err
== GIT_ITEROVER
)
1013 if (found
== 0 && err
== 0)
1014 err
= config_error_notfound(name
);
1020 git_config_iterator parent
;
1021 git_config_iterator
*iter
;
1027 static int multivar_iter_next(git_config_entry
**entry
, git_config_iterator
*_iter
)
1029 multivar_iter
*iter
= (multivar_iter
*) _iter
;
1032 while ((error
= iter
->iter
->next(entry
, iter
->iter
)) == 0) {
1033 if (git__strcmp(iter
->name
, (*entry
)->name
))
1036 if (!iter
->have_regex
)
1039 if (git_regexp_match(&iter
->regex
, (*entry
)->value
) == 0)
1046 static void multivar_iter_free(git_config_iterator
*_iter
)
1048 multivar_iter
*iter
= (multivar_iter
*) _iter
;
1050 iter
->iter
->free(iter
->iter
);
1052 git__free(iter
->name
);
1053 if (iter
->have_regex
)
1054 git_regexp_dispose(&iter
->regex
);
1058 int git_config_multivar_iterator_new(git_config_iterator
**out
, const git_config
*cfg
, const char *name
, const char *regexp
)
1060 multivar_iter
*iter
= NULL
;
1061 git_config_iterator
*inner
= NULL
;
1064 if ((error
= git_config_iterator_new(&inner
, cfg
)) < 0)
1067 iter
= git__calloc(1, sizeof(multivar_iter
));
1068 GIT_ERROR_CHECK_ALLOC(iter
);
1070 if ((error
= git_config__normalize_name(name
, &iter
->name
)) < 0)
1073 if (regexp
!= NULL
) {
1074 if ((error
= git_regexp_compile(&iter
->regex
, regexp
, 0)) < 0)
1077 iter
->have_regex
= 1;
1081 iter
->parent
.free
= multivar_iter_free
;
1082 iter
->parent
.next
= multivar_iter_next
;
1084 *out
= (git_config_iterator
*) iter
;
1095 int git_config_set_multivar(git_config
*cfg
, const char *name
, const char *regexp
, const char *value
)
1097 git_config_backend
*backend
;
1099 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_DELETE
) < 0)
1100 return GIT_ENOTFOUND
;
1102 return backend
->set_multivar(backend
, name
, regexp
, value
);
1105 int git_config_delete_multivar(git_config
*cfg
, const char *name
, const char *regexp
)
1107 git_config_backend
*backend
;
1109 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_DELETE
) < 0)
1110 return GIT_ENOTFOUND
;
1112 return backend
->del_multivar(backend
, name
, regexp
);
1115 int git_config_next(git_config_entry
**entry
, git_config_iterator
*iter
)
1117 return iter
->next(entry
, iter
);
1120 void git_config_iterator_free(git_config_iterator
*iter
)
1128 int git_config_find_global(git_buf
*path
)
1130 GIT_BUF_WRAP_PRIVATE(path
, git_sysdir_find_global_file
, GIT_CONFIG_FILENAME_GLOBAL
);
1133 int git_config__find_global(git_str
*path
)
1135 return git_sysdir_find_global_file(path
, GIT_CONFIG_FILENAME_GLOBAL
);
1138 int git_config_find_xdg(git_buf
*path
)
1140 GIT_BUF_WRAP_PRIVATE(path
, git_sysdir_find_xdg_file
, GIT_CONFIG_FILENAME_XDG
);
1143 int git_config__find_xdg(git_str
*path
)
1145 return git_sysdir_find_xdg_file(path
, GIT_CONFIG_FILENAME_XDG
);
1148 int git_config_find_system(git_buf
*path
)
1150 GIT_BUF_WRAP_PRIVATE(path
, git_sysdir_find_system_file
, GIT_CONFIG_FILENAME_SYSTEM
);
1153 int git_config__find_system(git_str
*path
)
1155 return git_sysdir_find_system_file(path
, GIT_CONFIG_FILENAME_SYSTEM
);
1158 int git_config_find_programdata(git_buf
*path
)
1160 git_str str
= GIT_STR_INIT
;
1163 if ((error
= git_buf_tostr(&str
, path
)) == 0 &&
1164 (error
= git_config__find_programdata(&str
)) == 0)
1165 error
= git_buf_fromstr(path
, &str
);
1167 git_str_dispose(&str
);
1171 int git_config__find_programdata(git_str
*path
)
1173 git_fs_path_owner_t owner_level
=
1174 GIT_FS_PATH_OWNER_CURRENT_USER
|
1175 GIT_FS_PATH_OWNER_ADMINISTRATOR
;
1178 if (git_sysdir_find_programdata_file(path
, GIT_CONFIG_FILENAME_PROGRAMDATA
) < 0 ||
1179 git_fs_path_owner_is(&is_safe
, path
->ptr
, owner_level
) < 0)
1183 git_error_set(GIT_ERROR_CONFIG
, "programdata path has invalid ownership");
1190 int git_config__global_location(git_str
*buf
)
1192 const git_str
*paths
;
1193 const char *sep
, *start
;
1195 if (git_sysdir_get(&paths
, GIT_SYSDIR_GLOBAL
) < 0)
1198 /* no paths, so give up */
1199 if (!paths
|| !git_str_len(paths
))
1202 /* find unescaped separator or end of string */
1203 for (sep
= start
= git_str_cstr(paths
); *sep
; ++sep
) {
1204 if (*sep
== GIT_PATH_LIST_SEPARATOR
&&
1205 (sep
<= start
|| sep
[-1] != '\\'))
1209 if (git_str_set(buf
, start
, (size_t)(sep
- start
)) < 0)
1212 return git_str_joinpath(buf
, buf
->ptr
, GIT_CONFIG_FILENAME_GLOBAL
);
1215 int git_config_open_default(git_config
**out
)
1218 git_config
*cfg
= NULL
;
1219 git_str buf
= GIT_STR_INIT
;
1221 if ((error
= git_config_new(&cfg
)) < 0)
1224 if (!git_config__find_global(&buf
) ||
1225 !git_config__global_location(&buf
)) {
1226 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1227 GIT_CONFIG_LEVEL_GLOBAL
, NULL
, 0);
1230 if (!error
&& !git_config__find_xdg(&buf
))
1231 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1232 GIT_CONFIG_LEVEL_XDG
, NULL
, 0);
1234 if (!error
&& !git_config__find_system(&buf
))
1235 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1236 GIT_CONFIG_LEVEL_SYSTEM
, NULL
, 0);
1238 if (!error
&& !git_config__find_programdata(&buf
))
1239 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1240 GIT_CONFIG_LEVEL_PROGRAMDATA
, NULL
, 0);
1242 git_str_dispose(&buf
);
1245 git_config_free(cfg
);
1254 int git_config_lock(git_transaction
**out
, git_config
*cfg
)
1257 git_config_backend
*backend
;
1258 backend_internal
*internal
;
1260 GIT_ASSERT_ARG(cfg
);
1262 internal
= git_vector_get(&cfg
->backends
, 0);
1263 if (!internal
|| !internal
->backend
) {
1264 git_error_set(GIT_ERROR_CONFIG
, "cannot lock; the config has no backends");
1267 backend
= internal
->backend
;
1269 if ((error
= backend
->lock(backend
)) < 0)
1272 return git_transaction_config_new(out
, cfg
);
1275 int git_config_unlock(git_config
*cfg
, int commit
)
1277 git_config_backend
*backend
;
1278 backend_internal
*internal
;
1280 GIT_ASSERT_ARG(cfg
);
1282 internal
= git_vector_get(&cfg
->backends
, 0);
1283 if (!internal
|| !internal
->backend
) {
1284 git_error_set(GIT_ERROR_CONFIG
, "cannot lock; the config has no backends");
1288 backend
= internal
->backend
;
1290 return backend
->unlock(backend
, commit
);
1297 int git_config_lookup_map_value(
1299 const git_configmap
*maps
,
1305 for (i
= 0; i
< map_n
; ++i
) {
1306 const git_configmap
*m
= maps
+ i
;
1309 case GIT_CONFIGMAP_FALSE
:
1310 case GIT_CONFIGMAP_TRUE
: {
1313 if (git_config_parse_bool(&bool_val
, value
) == 0 &&
1314 bool_val
== (int)m
->type
) {
1315 *out
= m
->map_value
;
1321 case GIT_CONFIGMAP_INT32
:
1322 if (git_config_parse_int32(out
, value
) == 0)
1326 case GIT_CONFIGMAP_STRING
:
1327 if (value
&& strcasecmp(value
, m
->str_match
) == 0) {
1328 *out
= m
->map_value
;
1335 git_error_set(GIT_ERROR_CONFIG
, "failed to map '%s'", value
);
1339 int git_config_lookup_map_enum(git_configmap_t
*type_out
, const char **str_out
,
1340 const git_configmap
*maps
, size_t map_n
, int enum_val
)
1344 for (i
= 0; i
< map_n
; i
++) {
1345 const git_configmap
*m
= &maps
[i
];
1347 if (m
->map_value
!= enum_val
)
1350 *type_out
= m
->type
;
1351 *str_out
= m
->str_match
;
1355 git_error_set(GIT_ERROR_CONFIG
, "invalid enum value");
1356 return GIT_ENOTFOUND
;
1359 int git_config_parse_bool(int *out
, const char *value
)
1361 if (git__parse_bool(out
, value
) == 0)
1364 if (git_config_parse_int32(out
, value
) == 0) {
1369 git_error_set(GIT_ERROR_CONFIG
, "failed to parse '%s' as a boolean value", value
);
1373 int git_config_parse_int64(int64_t *out
, const char *value
)
1375 const char *num_end
;
1378 if (!value
|| git__strntol64(&num
, value
, strlen(value
), &num_end
, 0) < 0)
1396 /* check that that there are no more characters after the
1397 * given modifier suffix */
1398 if (num_end
[1] != '\0')
1412 git_error_set(GIT_ERROR_CONFIG
, "failed to parse '%s' as an integer", value
? value
: "(null)");
1416 int git_config_parse_int32(int32_t *out
, const char *value
)
1421 if (git_config_parse_int64(&tmp
, value
) < 0)
1424 truncate
= tmp
& 0xFFFFFFFF;
1425 if (truncate
!= tmp
)
1432 git_error_set(GIT_ERROR_CONFIG
, "failed to parse '%s' as a 32-bit integer", value
? value
: "(null)");
1436 static int normalize_section(char *start
, char *end
)
1441 return GIT_EINVALIDSPEC
;
1443 /* Validate and downcase range */
1444 for (scan
= start
; *scan
; ++scan
) {
1445 if (end
&& scan
>= end
)
1448 *scan
= (char)git__tolower(*scan
);
1449 else if (*scan
!= '-' || scan
== start
)
1450 return GIT_EINVALIDSPEC
;
1454 return GIT_EINVALIDSPEC
;
1460 /* Take something the user gave us and make it nice for our hash function */
1461 int git_config__normalize_name(const char *in
, char **out
)
1463 char *name
, *fdot
, *ldot
;
1466 GIT_ASSERT_ARG(out
);
1468 name
= git__strdup(in
);
1469 GIT_ERROR_CHECK_ALLOC(name
);
1471 fdot
= strchr(name
, '.');
1472 ldot
= strrchr(name
, '.');
1474 if (fdot
== NULL
|| fdot
== name
|| ldot
== NULL
|| !ldot
[1])
1477 /* Validate and downcase up to first dot and after last dot */
1478 if (normalize_section(name
, fdot
) < 0 ||
1479 normalize_section(ldot
+ 1, NULL
) < 0)
1482 /* If there is a middle range, make sure it doesn't have newlines */
1484 if (*fdot
++ == '\n')
1492 git_error_set(GIT_ERROR_CONFIG
, "invalid config item name '%s'", in
);
1493 return GIT_EINVALIDSPEC
;
1496 struct rename_data
{
1502 static int rename_config_entries_cb(
1503 const git_config_entry
*entry
,
1507 struct rename_data
*data
= (struct rename_data
*)payload
;
1508 size_t base_len
= git_str_len(data
->name
);
1511 !(error
= git_str_puts(data
->name
, entry
->name
+ data
->old_len
)))
1513 error
= git_config_set_string(
1514 data
->config
, git_str_cstr(data
->name
), entry
->value
);
1516 git_str_truncate(data
->name
, base_len
);
1520 error
= git_config_delete_entry(data
->config
, entry
->name
);
1525 int git_config_rename_section(
1526 git_repository
*repo
,
1527 const char *old_section_name
,
1528 const char *new_section_name
)
1531 git_str pattern
= GIT_STR_INIT
, replace
= GIT_STR_INIT
;
1533 struct rename_data data
;
1535 git_str_puts_escape_regex(&pattern
, old_section_name
);
1537 if ((error
= git_str_puts(&pattern
, "\\..+")) < 0)
1540 if ((error
= git_repository_config__weakptr(&config
, repo
)) < 0)
1543 data
.config
= config
;
1544 data
.name
= &replace
;
1545 data
.old_len
= strlen(old_section_name
) + 1;
1547 if ((error
= git_str_join(&replace
, '.', new_section_name
, "")) < 0)
1550 if (new_section_name
!= NULL
&&
1551 (error
= normalize_section(replace
.ptr
, strchr(replace
.ptr
, '.'))) < 0)
1554 GIT_ERROR_CONFIG
, "invalid config section '%s'", new_section_name
);
1558 error
= git_config_foreach_match(
1559 config
, git_str_cstr(&pattern
), rename_config_entries_cb
, &data
);
1562 git_str_dispose(&pattern
);
1563 git_str_dispose(&replace
);
1568 int git_config_init_backend(git_config_backend
*backend
, unsigned int version
)
1570 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1571 backend
, version
, git_config_backend
, GIT_CONFIG_BACKEND_INIT
);