From e203e9d47268f4322fa801bf48769282b229c19b Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Sat, 19 May 2012 18:13:38 +0200 Subject: config: do not set an error for GIT_ENOTFOUND An unset config variable isn't bad per se -- let the call site set an error in case GIT_ENOTFOUND isn't acceptable. --- src/config.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 618202c34..d18b85c30 100644 --- a/src/config.c +++ b/src/config.c @@ -391,7 +391,6 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name) return ret; } - giterr_set(GITERR_CONFIG, "Config variable '%s' not found", name); return GIT_ENOTFOUND; } -- cgit v1.2.3 From b3ff1dab317dc9194c4bc124afd95ae9be2ad57b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 15:22:39 -0700 Subject: Adding git_config_foreach_match() iteration fn Adding a new config iteration function that let's you iterate over just the config entries that match a particular regular expression. The old foreach becomes a simple use of this with an empty pattern. This also fixes an apparent bug in the existing `git_config_foreach` where returning a non-zero value from the iteration callback was not correctly aborting the iteration and the returned value was not being propogated back to the caller of foreach. Added to tests to cover all these changes. --- src/config.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index d18b85c30..98fb3b20d 100644 --- a/src/config.c +++ b/src/config.c @@ -136,17 +136,27 @@ int git_config_add_file(git_config *cfg, git_config_file *file, int priority) * Loop over all the variables */ -int git_config_foreach(git_config *cfg, int (*fn)(const char *, const char *, void *), void *data) +int git_config_foreach( + git_config *cfg, int (*fn)(const char *, const char *, void *), void *data) +{ + return git_config_foreach_match(cfg, NULL, fn, data); +} + +int git_config_foreach_match( + git_config *cfg, + const char *regexp, + int (*fn)(const char *, const char *, void *), + void *data) { int ret = 0; unsigned int i; file_internal *internal; git_config_file *file; - for(i = 0; i < cfg->files.length && ret == 0; ++i) { + for (i = 0; i < cfg->files.length && ret == 0; ++i) { internal = git_vector_get(&cfg->files, i); file = internal->file; - ret = file->foreach(file, fn, data); + ret = file->foreach(file, regexp, fn, data); } return ret; -- cgit v1.2.3 From b8457baae24269c9fb777591e2a0e1b425ba31b6 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 24 Jul 2012 07:57:58 +0200 Subject: portability: Improve x86/amd64 compatibility --- src/config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 98fb3b20d..44cfe760c 100644 --- a/src/config.c +++ b/src/config.c @@ -410,7 +410,7 @@ int git_config_get_multivar(git_config *cfg, const char *name, const char *regex file_internal *internal; git_config_file *file; int ret = GIT_ENOTFOUND; - unsigned int i; + size_t i; assert(cfg->files.length); @@ -434,7 +434,7 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex file_internal *internal; git_config_file *file; int ret = GIT_ENOTFOUND; - unsigned int i; + size_t i; for (i = cfg->files.length; i > 0; --i) { internal = git_vector_get(&cfg->files, i - 1); -- cgit v1.2.3 From ca1b6e54095a7e28d468a832f143025feae6cd4f Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 31 Jul 2012 17:02:54 -0700 Subject: Add template dir and set gid to repo init This extends git_repository_init_ext further with support for initializing the repository from an external template directory and with support for the "create shared" type flags that make a set GID repository directory. This also adds tests for much of the new functionality to the existing `repo/init.c` test suite. Also, this adds a bunch of new utility functions including a very general purpose `git_futils_mkdir` (with the ability to make paths and to chmod the paths post-creation) and a file tree copying function `git_futils_cp_r`. Also, this includes some new path functions that were useful to keep the code simple. --- src/config.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 44cfe760c..3ca49714c 100644 --- a/src/config.c +++ b/src/config.c @@ -515,3 +515,28 @@ int git_config_open_global(git_config **out) return error; } +int git_config_open_outside_repo(git_config **out) +{ + int error; + git_config *cfg = NULL; + git_buf buf = GIT_BUF_INIT; + + error = git_config_new(&cfg); + + if (!error && !git_config_find_global_r(&buf)) + error = git_config_add_file_ondisk(cfg, buf.ptr, 2); + + if (!error && !git_config_find_system_r(&buf)) + error = git_config_add_file_ondisk(cfg, buf.ptr, 1); + + git_buf_free(&buf); + + if (error && cfg) { + git_config_free(cfg); + cfg = NULL; + } + + *out = cfg; + + return error; +} -- cgit v1.2.3 From 85bd17462662905dfdf9247b262480280a616ad4 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 22 Aug 2012 16:03:35 -0700 Subject: Some cleanup suggested during review This cleans up a number of items suggested during code review with @vmg, including: * renaming "outside repo" config API to `git_config_open_default` * killing the `git_config_open_global` API * removing the `git_` prefix from the static functions in fileops * removing some unnecessary functionality from the "cp" command --- src/config.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 3ca49714c..277daaafe 100644 --- a/src/config.c +++ b/src/config.c @@ -501,21 +501,7 @@ int git_config_find_system(char *system_config_path, size_t length) return 0; } -int git_config_open_global(git_config **out) -{ - int error; - git_buf path = GIT_BUF_INIT; - - if ((error = git_config_find_global_r(&path)) < 0) - return error; - - error = git_config_open_ondisk(out, git_buf_cstr(&path)); - git_buf_free(&path); - - return error; -} - -int git_config_open_outside_repo(git_config **out) +int git_config_open_default(git_config **out) { int error; git_config *cfg = NULL; -- cgit v1.2.3 From 7fbca880aa5c011257ef734d0b5bfd5545dbaf6b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 24 Aug 2012 14:32:45 -0700 Subject: Support new config locations As of git v1.7.12, $HOME/.config/git/ is supported as a new location for "config", "attributes", and "ignore" files. --- src/config.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 277daaafe..e62dccf51 100644 --- a/src/config.c +++ b/src/config.c @@ -449,7 +449,12 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex int git_config_find_global_r(git_buf *path) { - return git_futils_find_global_file(path, GIT_CONFIG_FILENAME); + int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME); + + if (error == GIT_ENOTFOUND) + error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); + + return error; } int git_config_find_global(char *global_config_path, size_t length) -- cgit v1.2.3 From 8b4f9b17580c52ac2b1f2f42f5c53116fb763436 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Mon, 24 Sep 2012 18:59:00 +0200 Subject: Correctly read xdr compatible %HOME%/.config/git/config config file This file is not just read if the global config file (%HOME%/.gitconfig) is not found, however, it is used everytime but with lower priority. Signed-off-by: Sven Strickroth --- src/config.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index e62dccf51..b3d6fc69a 100644 --- a/src/config.c +++ b/src/config.c @@ -451,8 +451,12 @@ int git_config_find_global_r(git_buf *path) { int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME); - if (error == GIT_ENOTFOUND) - error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); + return error; +} + +int git_config_find_xdr_r(git_buf *path) +{ + int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); return error; } -- cgit v1.2.3 From d7940ac3e4afd92fca527aafcc13a88817c5670f Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 25 Sep 2012 00:09:44 +0200 Subject: Fixed missing method Signed-off-by: Sven Strickroth --- src/config.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index b3d6fc69a..e9854731b 100644 --- a/src/config.c +++ b/src/config.c @@ -483,6 +483,28 @@ int git_config_find_global(char *global_config_path, size_t length) return 0; } +int git_config_find_xdr(char *xdr_config_path, size_t length) +{ + git_buf path = GIT_BUF_INIT; + int ret = git_config_find_xdr_r(&path); + + if (ret < 0) { + git_buf_free(&path); + return ret; + } + + if (path.size >= length) { + git_buf_free(&path); + giterr_set(GITERR_NOMEMORY, + "Path is to long to fit on the given buffer"); + return -1; + } + + git_buf_copy_cstr(xdr_config_path, length, &path); + git_buf_free(&path); + return 0; +} + int git_config_find_system_r(git_buf *path) { return git_futils_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); -- cgit v1.2.3 From c378a1184e8e4cdcffcad3271d650ab12792a6bc Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 25 Sep 2012 00:11:53 +0200 Subject: git_config_open_default: Honour xdr config Signed-off-by: Sven Strickroth --- src/config.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index e9854731b..d8e54751a 100644 --- a/src/config.c +++ b/src/config.c @@ -541,6 +541,9 @@ int git_config_open_default(git_config **out) error = git_config_new(&cfg); if (!error && !git_config_find_global_r(&buf)) + error = git_config_add_file_ondisk(cfg, buf.ptr, 3); + + if (!error && !git_config_find_xdr_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, 2); if (!error && !git_config_find_system_r(&buf)) -- cgit v1.2.3 From 4258d4832b9525ed4e21597a9e63a6dd5aa43507 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 2 Oct 2012 17:21:07 +0200 Subject: Rename xdr to xdg Signed-off-by: Sven Strickroth --- src/config.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index d8e54751a..b89c16b1c 100644 --- a/src/config.c +++ b/src/config.c @@ -454,7 +454,7 @@ int git_config_find_global_r(git_buf *path) return error; } -int git_config_find_xdr_r(git_buf *path) +int git_config_find_xdg_r(git_buf *path) { int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); @@ -483,10 +483,10 @@ int git_config_find_global(char *global_config_path, size_t length) return 0; } -int git_config_find_xdr(char *xdr_config_path, size_t length) +int git_config_find_xdg(char *xdg_config_path, size_t length) { git_buf path = GIT_BUF_INIT; - int ret = git_config_find_xdr_r(&path); + int ret = git_config_find_xdg_r(&path); if (ret < 0) { git_buf_free(&path); @@ -500,7 +500,7 @@ int git_config_find_xdr(char *xdr_config_path, size_t length) return -1; } - git_buf_copy_cstr(xdr_config_path, length, &path); + git_buf_copy_cstr(xdg_config_path, length, &path); git_buf_free(&path); return 0; } @@ -543,7 +543,7 @@ int git_config_open_default(git_config **out) if (!error && !git_config_find_global_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, 3); - if (!error && !git_config_find_xdr_r(&buf)) + if (!error && !git_config_find_xdg_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, 2); if (!error && !git_config_find_system_r(&buf)) -- cgit v1.2.3 From a1abe66aca3625eec1cabb2e93cf8df0be1b63f0 Mon Sep 17 00:00:00 2001 From: yorah Date: Mon, 10 Sep 2012 12:11:02 +0200 Subject: Add config level support in the config API Added `struct git_config_entry`: a git_config_entry contains the key, the value, and the config file level from which a config element was found. Added `git_config_open_level`: build a single-level focused config object from a multi-level one. We are now storing `git_config_entry`s in the khash of the config_file --- src/config.c | 502 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 331 insertions(+), 171 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index b89c16b1c..f9bd205af 100644 --- a/src/config.c +++ b/src/config.c @@ -17,21 +17,29 @@ #include typedef struct { + git_refcount rc; + git_config_file *file; - int priority; + unsigned int level; } file_internal; +static void file_internal_free(file_internal *internal) +{ + git_config_file *file; + + file = internal->file; + file->free(file); + git__free(internal); +} + static void config_free(git_config *cfg) { unsigned int i; - git_config_file *file; file_internal *internal; for(i = 0; i < cfg->files.length; ++i){ internal = git_vector_get(&cfg->files, i); - file = internal->file; - file->free(file); - git__free(internal); + GIT_REFCOUNT_DEC(internal, file_internal_free); } git_vector_free(&cfg->files); @@ -51,7 +59,7 @@ static int config_backend_cmp(const void *a, const void *b) const file_internal *bk_a = (const file_internal *)(a); const file_internal *bk_b = (const file_internal *)(b); - return bk_b->priority - bk_a->priority; + return bk_b->level - bk_a->level; } int git_config_new(git_config **out) @@ -73,20 +81,25 @@ int git_config_new(git_config **out) return 0; } -int git_config_add_file_ondisk(git_config *cfg, const char *path, int priority) +int git_config_add_file_ondisk( + git_config *cfg, + const char *path, + unsigned int level, + int force) { git_config_file *file = NULL; + int res; if (git_config_file__ondisk(&file, path) < 0) return -1; - if (git_config_add_file(cfg, file, priority) < 0) { + if ((res = git_config_add_file(cfg, file, level, force)) < 0) { /* * free manually; the file is not owned by the config * instance yet and will not be freed on cleanup */ file->free(file); - return -1; + return res; } return 0; @@ -97,7 +110,7 @@ int git_config_open_ondisk(git_config **cfg, const char *path) if (git_config_new(cfg) < 0) return -1; - if (git_config_add_file_ondisk(*cfg, path, 1) < 0) { + if (git_config_add_file_ondisk(*cfg, path, GIT_CONFIG_LEVEL_LOCAL, 0) < 0) { git_config_free(*cfg); return -1; } @@ -105,30 +118,152 @@ int git_config_open_ondisk(git_config **cfg, const char *path) return 0; } -int git_config_add_file(git_config *cfg, git_config_file *file, int priority) +static int find_internal_file_by_level( + file_internal **internal_out, + git_config *cfg, + int level) +{ + int pos = -1; + file_internal *internal; + unsigned int i; + + assert(cfg->files.length); + + /* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config file + * which has the highest level. As config files are stored in a vector + * sorted by decreasing order of level, getting the file at position 0 + * will do the job. + */ + if (level == GIT_CONFIG_HIGHEST_LEVEL) { + pos = 0; + } else { + git_vector_foreach(&cfg->files, i, internal) { + if (internal->level == (unsigned int)level) + pos = i; + } + } + + if (pos == -1) { + giterr_set(GITERR_CONFIG, + "No config file exists for the given level '%i'", level); + return GIT_ENOTFOUND; + } + + *internal_out = git_vector_get(&cfg->files, pos); + + return 0; +} + +static int duplicate_level(void **old_raw, void *new_raw) +{ + file_internal **old = (file_internal **)old_raw; + + GIT_UNUSED(new_raw); + + giterr_set(GITERR_CONFIG, "A file with the same level (%i) has already been added to the config", (*old)->level); + return GIT_EEXISTS; +} + +static void try_remove_existing_file_internal( + git_config *cfg, + unsigned int level) +{ + int pos = -1; + file_internal *internal; + unsigned int i; + + git_vector_foreach(&cfg->files, i, internal) { + if (internal->level == level) + pos = i; + } + + if (pos == -1) + return; + + internal = git_vector_get(&cfg->files, pos); + + if (git_vector_remove(&cfg->files, pos) < 0) + return; + + GIT_REFCOUNT_DEC(internal, file_internal_free); +} + +static int git_config__add_internal( + git_config *cfg, + file_internal *internal, + unsigned int level, + int force) +{ + int result; + + /* delete existing config file for level if it exists */ + if (force) + try_remove_existing_file_internal(cfg, level); + + if ((result = git_vector_insert_sorted(&cfg->files, + internal, &duplicate_level)) < 0) + return result; + + git_vector_sort(&cfg->files); + internal->file->cfg = cfg; + + GIT_REFCOUNT_INC(internal); + + return 0; +} + +int git_config_open_level( + git_config **cfg_out, + git_config *cfg_parent, + unsigned int level) +{ + git_config *cfg; + file_internal *internal; + int res; + + if ((res = find_internal_file_by_level(&internal, cfg_parent, level)) < 0) + return res; + + if ((res = git_config_new(&cfg)) < 0) + return res; + + if ((res = git_config__add_internal(cfg, internal, level, true)) < 0) { + git_config_free(cfg); + return res; + } + + *cfg_out = cfg; + + return 0; +} + +int git_config_add_file( + git_config *cfg, + git_config_file *file, + unsigned int level, + int force) { file_internal *internal; int result; assert(cfg && file); - if ((result = file->open(file)) < 0) + if ((result = file->open(file, level)) < 0) return result; internal = git__malloc(sizeof(file_internal)); GITERR_CHECK_ALLOC(internal); + memset(internal, 0x0, sizeof(file_internal)); + internal->file = file; - internal->priority = priority; + internal->level = level; - if (git_vector_insert(&cfg->files, internal) < 0) { + if ((result = git_config__add_internal(cfg, internal, level, force)) < 0) { git__free(internal); - return -1; + return result; } - git_vector_sort(&cfg->files); - internal->file->cfg = cfg; - return 0; } @@ -137,7 +272,7 @@ int git_config_add_file(git_config *cfg, git_config_file *file, int priority) */ int git_config_foreach( - git_config *cfg, int (*fn)(const char *, const char *, void *), void *data) + git_config *cfg, int (*fn)(const git_config_entry *, void *), void *data) { return git_config_foreach_match(cfg, NULL, fn, data); } @@ -145,7 +280,7 @@ int git_config_foreach( int git_config_foreach_match( git_config *cfg, const char *regexp, - int (*fn)(const char *, const char *, void *), + int (*fn)(const git_config_entry *, void *), void *data) { int ret = 0; @@ -164,10 +299,8 @@ int git_config_foreach_match( int git_config_delete(git_config *cfg, const char *name) { - file_internal *internal; git_config_file *file; - - assert(cfg->files.length); + file_internal *internal; internal = git_vector_get(&cfg->files, 0); file = internal->file; @@ -198,10 +331,8 @@ int git_config_set_bool(git_config *cfg, const char *name, int value) int git_config_set_string(git_config *cfg, const char *name, const char *value) { - file_internal *internal; git_config_file *file; - - assert(cfg->files.length); + file_internal *internal; internal = git_vector_get(&cfg->files, 0); file = internal->file; @@ -209,105 +340,9 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) return file->set(file, name, value); } -static int parse_int64(int64_t *out, const char *value) -{ - const char *num_end; - int64_t num; - - if (git__strtol64(&num, value, &num_end, 0) < 0) - return -1; - - switch (*num_end) { - case 'g': - case 'G': - num *= 1024; - /* fallthrough */ - - case 'm': - case 'M': - num *= 1024; - /* fallthrough */ - - case 'k': - case 'K': - num *= 1024; - - /* check that that there are no more characters after the - * given modifier suffix */ - if (num_end[1] != '\0') - return -1; - - /* fallthrough */ - - case '\0': - *out = num; - return 0; - - default: - return -1; - } -} - -static int parse_int32(int32_t *out, const char *value) -{ - int64_t tmp; - int32_t truncate; - - if (parse_int64(&tmp, value) < 0) - return -1; - - truncate = tmp & 0xFFFFFFFF; - if (truncate != tmp) - return -1; - - *out = truncate; - return 0; -} - /*********** * Getters ***********/ -int git_config_lookup_map_value( - git_cvar_map *maps, size_t map_n, const char *value, int *out) -{ - size_t i; - - if (!value) - return GIT_ENOTFOUND; - - for (i = 0; i < map_n; ++i) { - git_cvar_map *m = maps + i; - - switch (m->cvar_type) { - case GIT_CVAR_FALSE: - case GIT_CVAR_TRUE: { - int bool_val; - - if (git__parse_bool(&bool_val, value) == 0 && - bool_val == (int)m->cvar_type) { - *out = m->map_value; - return 0; - } - break; - } - - case GIT_CVAR_INT32: - if (parse_int32(out, value) == 0) - return 0; - break; - - case GIT_CVAR_STRING: - if (strcasecmp(value, m->str_match) == 0) { - *out = m->map_value; - return 0; - } - break; - } - } - - return GIT_ENOTFOUND; -} - int git_config_get_mapped( int *out, git_config *cfg, @@ -318,16 +353,10 @@ int git_config_get_mapped( const char *value; int ret; - ret = git_config_get_string(&value, cfg, name); - if (ret < 0) + if ((ret = git_config_get_string(&value, cfg, name)) < 0) return ret; - if (!git_config_lookup_map_value(maps, map_n, value, out)) - return 0; - - giterr_set(GITERR_CONFIG, - "Failed to map the '%s' config variable with a valid value", name); - return -1; + return git_config_lookup_map_value(out, maps, map_n, value); } int git_config_get_int64(int64_t *out, git_config *cfg, const char *name) @@ -335,16 +364,10 @@ int git_config_get_int64(int64_t *out, git_config *cfg, const char *name) const char *value; int ret; - ret = git_config_get_string(&value, cfg, name); - if (ret < 0) + if ((ret = git_config_get_string(&value, cfg, name)) < 0) return ret; - if (parse_int64(out, value) < 0) { - giterr_set(GITERR_CONFIG, "Failed to parse '%s' as an integer", value); - return -1; - } - - return 0; + return git_config_parse_int64(out, value); } int git_config_get_int32(int32_t *out, git_config *cfg, const char *name) @@ -352,16 +375,10 @@ int git_config_get_int32(int32_t *out, git_config *cfg, const char *name) const char *value; int ret; - ret = git_config_get_string(&value, cfg, name); - if (ret < 0) + if ((ret = git_config_get_string(&value, cfg, name)) < 0) return ret; - if (parse_int32(out, value) < 0) { - giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value); - return -1; - } - - return 0; + return git_config_parse_int32(out, value); } int git_config_get_bool(int *out, git_config *cfg, const char *name) @@ -369,20 +386,24 @@ int git_config_get_bool(int *out, git_config *cfg, const char *name) const char *value; int ret; - ret = git_config_get_string(&value, cfg, name); - if (ret < 0) + if ((ret = git_config_get_string(&value, cfg, name)) < 0) return ret; - if (git__parse_bool(out, value) == 0) - return 0; + return git_config_parse_bool(out, value); +} - if (parse_int32(out, value) == 0) { - *out = !!(*out); - return 0; - } +static int get_string_at_file(const char **out, git_config_file *file, const char *name) +{ + const git_config_entry *entry; + int res; - giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a boolean value", value); - return -1; + *out = NULL; + + res = file->get(file, name, &entry); + if (res != GIT_ENOTFOUND) + *out = entry->value; + + return res; } int git_config_get_string(const char **out, git_config *cfg, const char *name) @@ -392,6 +413,23 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name) assert(cfg->files.length); + git_vector_foreach(&cfg->files, i, internal) { + int res = get_string_at_file(out, internal->file, name); + + if (res != GIT_ENOTFOUND) + return res; + } + + return GIT_ENOTFOUND; +} + +int git_config_get_config_entry(const git_config_entry **out, git_config *cfg, const char *name) +{ + file_internal *internal; + unsigned int i; + + assert(cfg->files.length); + *out = NULL; git_vector_foreach(&cfg->files, i, internal) { @@ -405,7 +443,7 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name) } int git_config_get_multivar(git_config *cfg, const char *name, const char *regexp, - int (*fn)(const char *value, void *data), void *data) + int (*fn)(const git_config_entry *entry, void *data), void *data) { file_internal *internal; git_config_file *file; @@ -431,20 +469,13 @@ int git_config_get_multivar(git_config *cfg, const char *name, const char *regex int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) { - file_internal *internal; git_config_file *file; - int ret = GIT_ENOTFOUND; - size_t i; + file_internal *internal; - for (i = cfg->files.length; i > 0; --i) { - internal = git_vector_get(&cfg->files, i - 1); - file = internal->file; - ret = file->set_multivar(file, name, regexp, value); - if (ret < 0 && ret != GIT_ENOTFOUND) - return ret; - } + internal = git_vector_get(&cfg->files, 0); + file = internal->file; - return 0; + return file->set_multivar(file, name, regexp, value); } int git_config_find_global_r(git_buf *path) @@ -541,13 +572,16 @@ int git_config_open_default(git_config **out) error = git_config_new(&cfg); if (!error && !git_config_find_global_r(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, 3); + error = git_config_add_file_ondisk(cfg, buf.ptr, + GIT_CONFIG_LEVEL_GLOBAL, 0); if (!error && !git_config_find_xdg_r(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, 2); + error = git_config_add_file_ondisk(cfg, buf.ptr, + GIT_CONFIG_LEVEL_XDG, 0); if (!error && !git_config_find_system_r(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, 1); + error = git_config_add_file_ondisk(cfg, buf.ptr, + GIT_CONFIG_LEVEL_SYSTEM, 0); git_buf_free(&buf); @@ -560,3 +594,129 @@ int git_config_open_default(git_config **out) return error; } + +/*********** + * Parsers + ***********/ +int git_config_lookup_map_value( + int *out, + git_cvar_map *maps, + size_t map_n, + const char *value) +{ + size_t i; + + if (!value) + goto fail_parse; + + for (i = 0; i < map_n; ++i) { + git_cvar_map *m = maps + i; + + switch (m->cvar_type) { + case GIT_CVAR_FALSE: + case GIT_CVAR_TRUE: { + int bool_val; + + if (git__parse_bool(&bool_val, value) == 0 && + bool_val == (int)m->cvar_type) { + *out = m->map_value; + return 0; + } + break; + } + + case GIT_CVAR_INT32: + if (git_config_parse_int32(out, value) == 0) + return 0; + break; + + case GIT_CVAR_STRING: + if (strcasecmp(value, m->str_match) == 0) { + *out = m->map_value; + return 0; + } + break; + } + } + +fail_parse: + giterr_set(GITERR_CONFIG, "Failed to map '%s'", value); + return -1; +} + +int git_config_parse_bool(int *out, const char *value) +{ + if (git__parse_bool(out, value) == 0) + return 0; + + if (git_config_parse_int32(out, value) == 0) { + *out = !!(*out); + return 0; + } + + giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a boolean value", value); + return -1; +} + +int git_config_parse_int64(int64_t *out, const char *value) +{ + const char *num_end; + int64_t num; + + if (git__strtol64(&num, value, &num_end, 0) < 0) + goto fail_parse; + + switch (*num_end) { + case 'g': + case 'G': + num *= 1024; + /* fallthrough */ + + case 'm': + case 'M': + num *= 1024; + /* fallthrough */ + + case 'k': + case 'K': + num *= 1024; + + /* check that that there are no more characters after the + * given modifier suffix */ + if (num_end[1] != '\0') + return -1; + + /* fallthrough */ + + case '\0': + *out = num; + return 0; + + default: + goto fail_parse; + } + +fail_parse: + giterr_set(GITERR_CONFIG, "Failed to parse '%s' as an integer", value); + return -1; +} + +int git_config_parse_int32(int32_t *out, const char *value) +{ + int64_t tmp; + int32_t truncate; + + if (git_config_parse_int64(&tmp, value) < 0) + goto fail_parse; + + truncate = tmp & 0xFFFFFFFF; + if (truncate != tmp) + goto fail_parse; + + *out = truncate; + return 0; + +fail_parse: + giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value); + return -1; +} -- cgit v1.2.3 From aba70781771061e8f6df78f2af3f9ac395dd5f57 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 11 Sep 2012 18:11:26 +0200 Subject: config: introduce git_config_rename_section() --- src/config.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index f9bd205af..377bbaf87 100644 --- a/src/config.c +++ b/src/config.c @@ -720,3 +720,81 @@ fail_parse: giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value); return -1; } + +struct rename_data +{ + git_config *config; + const char *old_name; + const char *new_name; +}; + +static int rename_config_entries_cb( + const git_config_entry *entry, + void *payload) +{ + struct rename_data *data = (struct rename_data *)payload; + + if (data->new_name != NULL) { + git_buf name = GIT_BUF_INIT; + int error; + + if (git_buf_printf( + &name, + "%s.%s", + data->new_name, + entry->name + strlen(data->old_name) + 1) < 0) + return -1; + + error = git_config_set_string( + data->config, + git_buf_cstr(&name), + entry->value); + + git_buf_free(&name); + + if (error) + return error; + } + + return git_config_delete(data->config, entry->name); +} + +int git_config_rename_section( + git_repository *repo, + const char *old_section_name, + const char *new_section_name) +{ + git_config *config; + git_buf pattern = GIT_BUF_INIT; + int error = -1; + struct rename_data data; + + git_buf_puts_escape_regex(&pattern, old_section_name); + git_buf_puts(&pattern, "\\..+"); + if (git_buf_oom(&pattern)) + goto cleanup; + + if (git_repository_config__weakptr(&config, repo) < 0) + goto cleanup; + + data.config = config; + data.old_name = old_section_name; + data.new_name = new_section_name; + + if ((error = git_config_foreach_match( + config, + git_buf_cstr(&pattern), + rename_config_entries_cb, &data)) < 0) { + giterr_set(GITERR_CONFIG, + "Cannot rename config section '%s' to '%s'", + old_section_name, + new_section_name); + goto cleanup; + } + + error = 0; + +cleanup: + git_buf_free(&pattern); + return error; +} -- cgit v1.2.3 From 505f37b41a7d80c539a33d28aec947cd87bb1b6c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 25 Oct 2012 19:22:35 +0200 Subject: config: Only dereference value on success --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index f9bd205af..c85695f19 100644 --- a/src/config.c +++ b/src/config.c @@ -400,7 +400,7 @@ static int get_string_at_file(const char **out, git_config_file *file, const cha *out = NULL; res = file->get(file, name, &entry); - if (res != GIT_ENOTFOUND) + if (!res) *out = entry->value; return res; -- cgit v1.2.3 From 744cc03e2b6d77712bfcb504c272d2e646da650c Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 30 Oct 2012 12:10:36 -0700 Subject: Add git_config_refresh() API to reload config This adds a new API that allows users to reload the config if the file has changed on disk. A new config callback function to refresh the config was added. The modified time and file size are used to test if the file needs to be reloaded (and are now stored in the disk backend object). In writing tests, just using mtime was a problem / race, so I wanted to check file size as well. To support that, I extended `git_futils_readbuffer_updated` to optionally check file size in addition to mtime, and I added a new function `git_filebuf_stats` to fetch the mtime and size for an open filebuf (so that the config could be easily refreshed after a write). Lastly, I moved some similar file checking code for attributes into filebuf. It is still only being used for attrs, but it seems potentially reusable, so I thought I'd move it over. --- src/config.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 937510d7e..033bde425 100644 --- a/src/config.c +++ b/src/config.c @@ -267,6 +267,20 @@ int git_config_add_file( return 0; } +int git_config_refresh(git_config *cfg) +{ + int error = 0; + unsigned int i; + + for (i = 0; i < cfg->files.length && !error; ++i) { + file_internal *internal = git_vector_get(&cfg->files, i); + git_config_file *file = internal->file; + error = file->refresh(file); + } + + return error; +} + /* * Loop over all the variables */ -- cgit v1.2.3 From 55f9837f11cae1d9c56e9f81eba3a3b7553ec8dd Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 9 Nov 2012 21:49:50 +0100 Subject: config: make git_config_open_level() work with an empty config --- src/config.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 033bde425..9945aaed7 100644 --- a/src/config.c +++ b/src/config.c @@ -127,8 +127,6 @@ static int find_internal_file_by_level( file_internal *internal; unsigned int i; - assert(cfg->files.length); - /* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config file * which has the highest level. As config files are stored in a vector * sorted by decreasing order of level, getting the file at position 0 -- cgit v1.2.3 From 3ee078c0f7ed278be4839a6bde7dce29a614d336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 13 Nov 2012 13:46:17 -0800 Subject: config: rename get_config_entry -> config_entry We're already in the git_config namespace, there is no need to repeat it. --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 9945aaed7..ed9901bd2 100644 --- a/src/config.c +++ b/src/config.c @@ -435,7 +435,7 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name) return GIT_ENOTFOUND; } -int git_config_get_config_entry(const git_config_entry **out, git_config *cfg, const char *name) +int git_config_get_entry(const git_config_entry **out, git_config *cfg, const char *name) { file_internal *internal; unsigned int i; -- cgit v1.2.3 From 0da81d2b39290fe4d444953acb6d68795ed1ef42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 13 Nov 2012 14:43:23 -0800 Subject: config: return an emtpy string when there is no value Returning NULL for the string when we haven't signaled an error condition is counter-intuitive and causes unnecessary edge cases. Return an empty string when asking for a string value for a configuration variable such as '[section] var' to avoid these edge cases. If the distinction between no value and an empty value is needed, this can be retrieved from the entry directly. As a side-effect, this change stops the int parsing functions from segfaulting on such a variable. --- src/config.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index ed9901bd2..4fb161169 100644 --- a/src/config.c +++ b/src/config.c @@ -393,24 +393,11 @@ int git_config_get_int32(int32_t *out, git_config *cfg, const char *name) return git_config_parse_int32(out, value); } -int git_config_get_bool(int *out, git_config *cfg, const char *name) -{ - const char *value; - int ret; - - if ((ret = git_config_get_string(&value, cfg, name)) < 0) - return ret; - - return git_config_parse_bool(out, value); -} - static int get_string_at_file(const char **out, git_config_file *file, const char *name) { const git_config_entry *entry; int res; - *out = NULL; - res = file->get(file, name, &entry); if (!res) *out = entry->value; @@ -418,7 +405,7 @@ static int get_string_at_file(const char **out, git_config_file *file, const cha return res; } -int git_config_get_string(const char **out, git_config *cfg, const char *name) +static int get_string(const char **out, git_config *cfg, const char *name) { file_internal *internal; unsigned int i; @@ -435,6 +422,29 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name) return GIT_ENOTFOUND; } +int git_config_get_bool(int *out, git_config *cfg, const char *name) +{ + const char *value; + int ret; + + if ((ret = get_string(&value, cfg, name)) < 0) + return ret; + + return git_config_parse_bool(out, value); +} + +int git_config_get_string(const char **out, git_config *cfg, const char *name) +{ + int ret; + const char *str; + + if ((ret = get_string(&str, cfg, name)) < 0) + return ret; + + *out = str == NULL ? "" : str; + return 0; +} + int git_config_get_entry(const git_config_entry **out, git_config *cfg, const char *name) { file_internal *internal; -- cgit v1.2.3 From 6132a54e0b4b3c5c9b03c0eba191bb756738d34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 13 Nov 2012 16:13:10 -0800 Subject: Fix a few valgrind errors --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 4fb161169..571a1f998 100644 --- a/src/config.c +++ b/src/config.c @@ -436,7 +436,7 @@ int git_config_get_bool(int *out, git_config *cfg, const char *name) int git_config_get_string(const char **out, git_config *cfg, const char *name) { int ret; - const char *str; + const char *str = NULL; if ((ret = get_string(&str, cfg, name)) < 0) return ret; -- cgit v1.2.3 From 0ec118280c5e0177492d494c6f628f8aec63587c Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Fri, 16 Nov 2012 02:17:57 +0100 Subject: Fix -Wmaybe-uninitialized warning --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 571a1f998..01a54ecf2 100644 --- a/src/config.c +++ b/src/config.c @@ -424,7 +424,7 @@ static int get_string(const char **out, git_config *cfg, const char *name) int git_config_get_bool(int *out, git_config *cfg, const char *name) { - const char *value; + const char *value = NULL; int ret; if ((ret = get_string(&value, cfg, name)) < 0) -- cgit v1.2.3 From 270160b91a0e55486f2cb6a6238c39fcd1271809 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 17 Nov 2012 13:39:24 -0800 Subject: config: Opening a nonexistent file returns ENOTFOUND --- src/config.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 01a54ecf2..412965b73 100644 --- a/src/config.c +++ b/src/config.c @@ -90,6 +90,13 @@ int git_config_add_file_ondisk( git_config_file *file = NULL; int res; + assert(cfg && path); + + if (!git_path_isfile(path)) { + giterr_set(GITERR_CONFIG, "File '%s' doesn't exists.", path); + return GIT_ENOTFOUND; + } + if (git_config_file__ondisk(&file, path) < 0) return -1; @@ -105,17 +112,22 @@ int git_config_add_file_ondisk( return 0; } -int git_config_open_ondisk(git_config **cfg, const char *path) +int git_config_open_ondisk(git_config **out, const char *path) { - if (git_config_new(cfg) < 0) - return -1; + int error; + git_config *config; - if (git_config_add_file_ondisk(*cfg, path, GIT_CONFIG_LEVEL_LOCAL, 0) < 0) { - git_config_free(*cfg); + *out = NULL; + + if (git_config_new(&config) < 0) return -1; - } - return 0; + if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0) + git_config_free(config); + else + *out = config; + + return error; } static int find_internal_file_by_level( -- cgit v1.2.3 From cc6b4162de59013b5357ec35a1806fc5c9b29148 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 20 Nov 2012 10:24:18 -0800 Subject: It is okay to not have a .gitconfig file Opening a repo is generating an error if you don't have a .gitconfig file in your home directory, but that should be legal. --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 412965b73..fc9ea65fe 100644 --- a/src/config.c +++ b/src/config.c @@ -93,7 +93,7 @@ int git_config_add_file_ondisk( assert(cfg && path); if (!git_path_isfile(path)) { - giterr_set(GITERR_CONFIG, "File '%s' doesn't exists.", path); + giterr_set(GITERR_CONFIG, "Cannot find config file '%s'", path); return GIT_ENOTFOUND; } -- cgit v1.2.3 From 54b2a37ac7715c74e5b06b76eb2b631987d7b6f8 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Tue, 20 Nov 2012 16:02:25 -0800 Subject: Clean up config.h --- src/config.c | 74 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index fc9ea65fe..5ee0d39ff 100644 --- a/src/config.c +++ b/src/config.c @@ -19,13 +19,13 @@ typedef struct { git_refcount rc; - git_config_file *file; + git_config_backend *file; unsigned int level; } file_internal; static void file_internal_free(file_internal *internal) { - git_config_file *file; + git_config_backend *file; file = internal->file; file->free(file); @@ -87,7 +87,7 @@ int git_config_add_file_ondisk( unsigned int level, int force) { - git_config_file *file = NULL; + git_config_backend *file = NULL; int res; assert(cfg && path); @@ -100,7 +100,7 @@ int git_config_add_file_ondisk( if (git_config_file__ondisk(&file, path) < 0) return -1; - if ((res = git_config_add_file(cfg, file, level, force)) < 0) { + if ((res = git_config_add_backend(cfg, file, level, force)) < 0) { /* * free manually; the file is not owned by the config * instance yet and will not be freed on cleanup @@ -132,7 +132,7 @@ int git_config_open_ondisk(git_config **out, const char *path) static int find_internal_file_by_level( file_internal **internal_out, - git_config *cfg, + const git_config *cfg, int level) { int pos = -1; @@ -224,7 +224,7 @@ static int git_config__add_internal( int git_config_open_level( git_config **cfg_out, - git_config *cfg_parent, + const git_config *cfg_parent, unsigned int level) { git_config *cfg; @@ -247,9 +247,9 @@ int git_config_open_level( return 0; } -int git_config_add_file( +int git_config_add_backend( git_config *cfg, - git_config_file *file, + git_config_backend *file, unsigned int level, int force) { @@ -284,7 +284,7 @@ int git_config_refresh(git_config *cfg) for (i = 0; i < cfg->files.length && !error; ++i) { file_internal *internal = git_vector_get(&cfg->files, i); - git_config_file *file = internal->file; + git_config_backend *file = internal->file; error = file->refresh(file); } @@ -296,34 +296,34 @@ int git_config_refresh(git_config *cfg) */ int git_config_foreach( - git_config *cfg, int (*fn)(const git_config_entry *, void *), void *data) + const git_config *cfg, git_config_foreach_cb cb, void *payload) { - return git_config_foreach_match(cfg, NULL, fn, data); + return git_config_foreach_match(cfg, NULL, cb, payload); } int git_config_foreach_match( - git_config *cfg, + const git_config *cfg, const char *regexp, - int (*fn)(const git_config_entry *, void *), - void *data) + git_config_foreach_cb cb, + void *payload) { int ret = 0; unsigned int i; file_internal *internal; - git_config_file *file; + git_config_backend *file; for (i = 0; i < cfg->files.length && ret == 0; ++i) { internal = git_vector_get(&cfg->files, i); file = internal->file; - ret = file->foreach(file, regexp, fn, data); + ret = file->foreach(file, regexp, cb, payload); } return ret; } -int git_config_delete(git_config *cfg, const char *name) +int git_config_delete_entry(git_config *cfg, const char *name) { - git_config_file *file; + git_config_backend *file; file_internal *internal; internal = git_vector_get(&cfg->files, 0); @@ -355,7 +355,7 @@ int git_config_set_bool(git_config *cfg, const char *name, int value) int git_config_set_string(git_config *cfg, const char *name, const char *value) { - git_config_file *file; + git_config_backend *file; file_internal *internal; internal = git_vector_get(&cfg->files, 0); @@ -369,9 +369,9 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) ***********/ int git_config_get_mapped( int *out, - git_config *cfg, + const git_config *cfg, const char *name, - git_cvar_map *maps, + const git_cvar_map *maps, size_t map_n) { const char *value; @@ -383,7 +383,7 @@ int git_config_get_mapped( return git_config_lookup_map_value(out, maps, map_n, value); } -int git_config_get_int64(int64_t *out, git_config *cfg, const char *name) +int git_config_get_int64(int64_t *out, const git_config *cfg, const char *name) { const char *value; int ret; @@ -394,7 +394,7 @@ int git_config_get_int64(int64_t *out, git_config *cfg, const char *name) return git_config_parse_int64(out, value); } -int git_config_get_int32(int32_t *out, git_config *cfg, const char *name) +int git_config_get_int32(int32_t *out, const git_config *cfg, const char *name) { const char *value; int ret; @@ -405,7 +405,7 @@ int git_config_get_int32(int32_t *out, git_config *cfg, const char *name) return git_config_parse_int32(out, value); } -static int get_string_at_file(const char **out, git_config_file *file, const char *name) +static int get_string_at_file(const char **out, const git_config_backend *file, const char *name) { const git_config_entry *entry; int res; @@ -417,7 +417,7 @@ static int get_string_at_file(const char **out, git_config_file *file, const cha return res; } -static int get_string(const char **out, git_config *cfg, const char *name) +static int get_string(const char **out, const git_config *cfg, const char *name) { file_internal *internal; unsigned int i; @@ -434,7 +434,7 @@ static int get_string(const char **out, git_config *cfg, const char *name) return GIT_ENOTFOUND; } -int git_config_get_bool(int *out, git_config *cfg, const char *name) +int git_config_get_bool(int *out, const git_config *cfg, const char *name) { const char *value = NULL; int ret; @@ -445,7 +445,7 @@ int git_config_get_bool(int *out, git_config *cfg, const char *name) return git_config_parse_bool(out, value); } -int git_config_get_string(const char **out, git_config *cfg, const char *name) +int git_config_get_string(const char **out, const git_config *cfg, const char *name) { int ret; const char *str = NULL; @@ -457,7 +457,7 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name) return 0; } -int git_config_get_entry(const git_config_entry **out, git_config *cfg, const char *name) +int git_config_get_entry(const git_config_entry **out, const git_config *cfg, const char *name) { file_internal *internal; unsigned int i; @@ -467,7 +467,7 @@ int git_config_get_entry(const git_config_entry **out, git_config *cfg, const ch *out = NULL; git_vector_foreach(&cfg->files, i, internal) { - git_config_file *file = internal->file; + git_config_backend *file = internal->file; int ret = file->get(file, name, out); if (ret != GIT_ENOTFOUND) return ret; @@ -476,11 +476,11 @@ int git_config_get_entry(const git_config_entry **out, git_config *cfg, const ch return GIT_ENOTFOUND; } -int git_config_get_multivar(git_config *cfg, const char *name, const char *regexp, - int (*fn)(const git_config_entry *entry, void *data), void *data) +int git_config_get_multivar(const git_config *cfg, const char *name, const char *regexp, + git_config_foreach_cb cb, void *payload) { file_internal *internal; - git_config_file *file; + git_config_backend *file; int ret = GIT_ENOTFOUND; size_t i; @@ -493,7 +493,7 @@ int git_config_get_multivar(git_config *cfg, const char *name, const char *regex for (i = cfg->files.length; i > 0; --i) { internal = git_vector_get(&cfg->files, i - 1); file = internal->file; - ret = file->get_multivar(file, name, regexp, fn, data); + ret = file->get_multivar(file, name, regexp, cb, payload); if (ret < 0 && ret != GIT_ENOTFOUND) return ret; } @@ -503,7 +503,7 @@ int git_config_get_multivar(git_config *cfg, const char *name, const char *regex int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) { - git_config_file *file; + git_config_backend *file; file_internal *internal; internal = git_vector_get(&cfg->files, 0); @@ -634,7 +634,7 @@ int git_config_open_default(git_config **out) ***********/ int git_config_lookup_map_value( int *out, - git_cvar_map *maps, + const git_cvar_map *maps, size_t map_n, const char *value) { @@ -644,7 +644,7 @@ int git_config_lookup_map_value( goto fail_parse; for (i = 0; i < map_n; ++i) { - git_cvar_map *m = maps + i; + const git_cvar_map *m = maps + i; switch (m->cvar_type) { case GIT_CVAR_FALSE: @@ -790,7 +790,7 @@ static int rename_config_entries_cb( return error; } - return git_config_delete(data->config, entry->name); + return git_config_delete_entry(data->config, entry->name); } int git_config_rename_section( -- cgit v1.2.3 From 7bf87ab6987cf6b9e166e23d2d9dbdcd2511fb32 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 28 Nov 2012 09:58:48 -0800 Subject: Consolidate text buffer functions There are many scattered functions that look into the contents of buffers to do various text manipulations (such as escaping or unescaping data, calculating text stats, guessing if content is binary, etc). This groups all those functions together into a new file and converts the code to use that. This has two enhancements to existing functionality. The old text stats function is significantly rewritten and the BOM detection code was extended (although largely we can't deal with anything other than a UTF8 BOM). --- src/config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 5ee0d39ff..6347f7df7 100644 --- a/src/config.c +++ b/src/config.c @@ -10,6 +10,7 @@ #include "config.h" #include "git2/config.h" #include "vector.h" +#include "buf_text.h" #if GIT_WIN32 # include #endif @@ -803,7 +804,7 @@ int git_config_rename_section( int error = -1; struct rename_data data; - git_buf_puts_escape_regex(&pattern, old_section_name); + git_buf_text_puts_escape_regex(&pattern, old_section_name); git_buf_puts(&pattern, "\\..+"); if (git_buf_oom(&pattern)) goto cleanup; -- cgit v1.2.3 From 691776213947e59a3928aab09e97a64b65e990ab Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Thu, 29 Nov 2012 14:07:50 -0800 Subject: Deploy git_config_backend version --- src/config.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 6347f7df7..913108abb 100644 --- a/src/config.c +++ b/src/config.c @@ -248,6 +248,18 @@ int git_config_open_level( return 0; } +static bool config_backend_has_valid_version(git_config_backend *backend) +{ + if (!backend) + return true; + + if (backend->version > 0 && backend->version <= GIT_CONFIG_BACKEND_VERSION) + return true; + + giterr_set(GITERR_INVALID, "Invalid version %d for git_config_backend", backend->version); + return false; +} + int git_config_add_backend( git_config *cfg, git_config_backend *file, @@ -259,6 +271,9 @@ int git_config_add_backend( assert(cfg && file); + if (!config_backend_has_valid_version(file)) + return -1; + if ((result = file->open(file, level)) < 0) return result; -- cgit v1.2.3 From c7231c45fecf6c0ae91815a82db7e98c94689497 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Fri, 30 Nov 2012 16:31:42 -0800 Subject: Deploy GITERR_CHECK_VERSION --- src/config.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 913108abb..d422447cf 100644 --- a/src/config.c +++ b/src/config.c @@ -248,18 +248,6 @@ int git_config_open_level( return 0; } -static bool config_backend_has_valid_version(git_config_backend *backend) -{ - if (!backend) - return true; - - if (backend->version > 0 && backend->version <= GIT_CONFIG_BACKEND_VERSION) - return true; - - giterr_set(GITERR_INVALID, "Invalid version %d for git_config_backend", backend->version); - return false; -} - int git_config_add_backend( git_config *cfg, git_config_backend *file, @@ -271,8 +259,7 @@ int git_config_add_backend( assert(cfg && file); - if (!config_backend_has_valid_version(file)) - return -1; + GITERR_CHECK_VERSION(file, GIT_CONFIG_BACKEND_VERSION, "git_config_backend"); if ((result = file->open(file, level)) < 0) return result; -- cgit v1.2.3 From 359fc2d241ac407bdf9bf0d28715705f01ca6360 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 8 Jan 2013 17:07:25 -0600 Subject: update copyrights --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index d422447cf..84f3ba0f9 100644 --- a/src/config.c +++ b/src/config.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 the libgit2 contributors + * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. -- cgit v1.2.3 From 1e7799e8b84491cadb99cc306749316beec8a339 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 29 Jan 2013 12:15:18 -0800 Subject: Implement config key validation rules This is a new implementation of core git's config key checking rules that prevents non-alphanumeric characters (and '-') for the top-level section and key names inside of config files. This also validates the target section name when renaming sections. --- src/config.c | 89 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 43 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 84f3ba0f9..ce105089e 100644 --- a/src/config.c +++ b/src/config.c @@ -11,6 +11,7 @@ #include "git2/config.h" #include "vector.h" #include "buf_text.h" +#include "config_file.h" #if GIT_WIN32 # include #endif @@ -758,42 +759,36 @@ fail_parse: return -1; } -struct rename_data -{ +struct rename_data { git_config *config; - const char *old_name; - const char *new_name; + git_buf *name; + size_t old_len; + int actual_error; }; static int rename_config_entries_cb( const git_config_entry *entry, void *payload) { + int error = 0; struct rename_data *data = (struct rename_data *)payload; + size_t base_len = git_buf_len(data->name); - if (data->new_name != NULL) { - git_buf name = GIT_BUF_INIT; - int error; - - if (git_buf_printf( - &name, - "%s.%s", - data->new_name, - entry->name + strlen(data->old_name) + 1) < 0) - return -1; - + if (base_len > 0 && + !(error = git_buf_puts(data->name, entry->name + data->old_len))) + { error = git_config_set_string( - data->config, - git_buf_cstr(&name), - entry->value); + data->config, git_buf_cstr(data->name), entry->value); - git_buf_free(&name); - - if (error) - return error; + git_buf_truncate(data->name, base_len); } - return git_config_delete_entry(data->config, entry->name); + if (!error) + error = git_config_delete_entry(data->config, entry->name); + + data->actual_error = error; /* preserve actual error code */ + + return error; } int git_config_rename_section( @@ -802,36 +797,44 @@ int git_config_rename_section( const char *new_section_name) { git_config *config; - git_buf pattern = GIT_BUF_INIT; - int error = -1; + git_buf pattern = GIT_BUF_INIT, replace = GIT_BUF_INIT; + int error = 0; struct rename_data data; - git_buf_text_puts_escape_regex(&pattern, old_section_name); - git_buf_puts(&pattern, "\\..+"); - if (git_buf_oom(&pattern)) + git_buf_text_puts_escape_regex(&pattern, old_section_name); + + if ((error = git_buf_puts(&pattern, "\\..+")) < 0) + goto cleanup; + + if ((error = git_repository_config__weakptr(&config, repo)) < 0) goto cleanup; - if (git_repository_config__weakptr(&config, repo) < 0) + data.config = config; + data.name = &replace; + data.old_len = strlen(old_section_name) + 1; + data.actual_error = 0; + + if ((error = git_buf_join(&replace, '.', new_section_name, "")) < 0) goto cleanup; - data.config = config; - data.old_name = old_section_name; - data.new_name = new_section_name; - - if ((error = git_config_foreach_match( - config, - git_buf_cstr(&pattern), - rename_config_entries_cb, &data)) < 0) { - giterr_set(GITERR_CONFIG, - "Cannot rename config section '%s' to '%s'", - old_section_name, - new_section_name); - goto cleanup; + if (new_section_name != NULL && + (error = git_config_file_normalize_section( + replace.ptr, strchr(replace.ptr, '.'))) < 0) + { + giterr_set( + GITERR_CONFIG, "Invalid config section '%s'", new_section_name); + goto cleanup; } - error = 0; + error = git_config_foreach_match( + config, git_buf_cstr(&pattern), rename_config_entries_cb, &data); + + if (error == GIT_EUSER) + error = data.actual_error; cleanup: git_buf_free(&pattern); + git_buf_free(&replace); + return error; } -- cgit v1.2.3 From 487fc724ffa0d0260fc4c2a3ab0ea0d5d2ebe81d Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 1 Mar 2013 13:41:53 -0800 Subject: Allow empty config object and use it This removes assertions that prevent us from having an empty git_config object and then updates some tests that were dependent on global config state to use an empty config before running anything. --- src/config.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index ce105089e..d6aa3078c 100644 --- a/src/config.c +++ b/src/config.c @@ -426,8 +426,6 @@ static int get_string(const char **out, const git_config *cfg, const char *name) file_internal *internal; unsigned int i; - assert(cfg->files.length); - git_vector_foreach(&cfg->files, i, internal) { int res = get_string_at_file(out, internal->file, name); @@ -466,8 +464,6 @@ int git_config_get_entry(const git_config_entry **out, const git_config *cfg, co file_internal *internal; unsigned int i; - assert(cfg->files.length); - *out = NULL; git_vector_foreach(&cfg->files, i, internal) { @@ -488,8 +484,6 @@ int git_config_get_multivar(const git_config *cfg, const char *name, const char int ret = GIT_ENOTFOUND; size_t i; - assert(cfg->files.length); - /* * This loop runs the "wrong" way 'round because we need to * look at every value from the most general to most specific -- cgit v1.2.3 From 48bde2f1b62d24f3982382d520bfac887537641d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 8 Mar 2013 02:11:34 +0100 Subject: config: don't allow passing NULL as a value to set Passing NULL is non-sensical. The error message leaves to be desired, though, as it leaks internal implementation details. Catch it at the `git_config_set_string` level and set an appropriate error message. --- src/config.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index d6aa3078c..c7022891d 100644 --- a/src/config.c +++ b/src/config.c @@ -362,6 +362,11 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) git_config_backend *file; file_internal *internal; + if (!value) { + giterr_set(GITERR_CONFIG, "The value to set cannot be NULL"); + return -1; + } + internal = git_vector_get(&cfg->files, 0); file = internal->file; -- cgit v1.2.3 From 5540d9477ed143707435324e785336d254b12e47 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 15 Mar 2013 16:39:00 -0700 Subject: Implement global/system file search paths The goal of this work is to expose the search logic for "global", "system", and "xdg" files through the git_libgit2_opts() interface. Behind the scenes, I changed the logic for finding files to have a notion of a git_strarray that represents a search path and to store a separate search path for each of the three tiers of config file. For each tier, I implemented a function to initialize it to default values (generally based on environment variables), and then general interfaces to get it, set it, reset it, and prepend new directories to it. Next, I exposed these interfaces through the git_libgit2_opts interface, reusing the GIT_CONFIG_LEVEL_SYSTEM, etc., constants for the user to control which search path they were modifying. There are alternative designs for the opts interface / argument ordering, so I'm putting this phase out for discussion. Additionally, I ended up doing a little bit of clean up regarding attr.h and attr_file.h, adding a new attrcache.h so the other two files wouldn't have to be included in so many places. --- src/config.c | 88 ++++++++++++++++++++---------------------------------------- 1 file changed, 29 insertions(+), 59 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index d6aa3078c..85db0ab3c 100644 --- a/src/config.c +++ b/src/config.c @@ -510,62 +510,48 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex return file->set_multivar(file, name, regexp, value); } -int git_config_find_global_r(git_buf *path) +static int git_config__find_file_to_path( + char *out, size_t outlen, int (*find)(git_buf *buf)) { - int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME); + int error = 0; + git_buf path = GIT_BUF_INIT; + + if ((error = find(&path)) < 0) + goto done; + + if (path.size >= outlen) { + giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path"); + error = -1; + goto done; + } + git_buf_copy_cstr(out, outlen, &path); + +done: + git_buf_free(&path); return error; } -int git_config_find_xdg_r(git_buf *path) +int git_config_find_global_r(git_buf *path) { - int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); - - return error; + return git_futils_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL); } int git_config_find_global(char *global_config_path, size_t length) { - git_buf path = GIT_BUF_INIT; - int ret = git_config_find_global_r(&path); - - if (ret < 0) { - git_buf_free(&path); - return ret; - } - - if (path.size >= length) { - git_buf_free(&path); - giterr_set(GITERR_NOMEMORY, - "Path is to long to fit on the given buffer"); - return -1; - } + return git_config__find_file_to_path( + global_config_path, length, git_config_find_global_r); +} - git_buf_copy_cstr(global_config_path, length, &path); - git_buf_free(&path); - return 0; +int git_config_find_xdg_r(git_buf *path) +{ + return git_futils_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG); } int git_config_find_xdg(char *xdg_config_path, size_t length) { - git_buf path = GIT_BUF_INIT; - int ret = git_config_find_xdg_r(&path); - - if (ret < 0) { - git_buf_free(&path); - return ret; - } - - if (path.size >= length) { - git_buf_free(&path); - giterr_set(GITERR_NOMEMORY, - "Path is to long to fit on the given buffer"); - return -1; - } - - git_buf_copy_cstr(xdg_config_path, length, &path); - git_buf_free(&path); - return 0; + return git_config__find_file_to_path( + xdg_config_path, length, git_config_find_xdg_r); } int git_config_find_system_r(git_buf *path) @@ -575,24 +561,8 @@ int git_config_find_system_r(git_buf *path) int git_config_find_system(char *system_config_path, size_t length) { - git_buf path = GIT_BUF_INIT; - int ret = git_config_find_system_r(&path); - - if (ret < 0) { - git_buf_free(&path); - return ret; - } - - if (path.size >= length) { - git_buf_free(&path); - giterr_set(GITERR_NOMEMORY, - "Path is to long to fit on the given buffer"); - return -1; - } - - git_buf_copy_cstr(system_config_path, length, &path); - git_buf_free(&path); - return 0; + return git_config__find_file_to_path( + system_config_path, length, git_config_find_system_r); } int git_config_open_default(git_config **out) -- cgit v1.2.3 From 10c06114cbb1c384b7de3cca6d6601ee750f5178 Mon Sep 17 00:00:00 2001 From: Arkadiy Shapkin Date: Sun, 17 Mar 2013 04:46:46 +0400 Subject: Several warnings detected by static code analyzer fixed Implicit type conversion argument of function to size_t type Suspicious sequence of types castings: size_t -> int -> size_t Consider reviewing the expression of the 'A = B == C' kind. The expression is calculated as following: 'A = (B == C)' Unsigned type is never < 0 --- src/config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index d6aa3078c..99b519d7d 100644 --- a/src/config.c +++ b/src/config.c @@ -36,7 +36,7 @@ static void file_internal_free(file_internal *internal) static void config_free(git_config *cfg) { - unsigned int i; + size_t i; file_internal *internal; for(i = 0; i < cfg->files.length; ++i){ @@ -284,7 +284,7 @@ int git_config_add_backend( int git_config_refresh(git_config *cfg) { int error = 0; - unsigned int i; + size_t i; for (i = 0; i < cfg->files.length && !error; ++i) { file_internal *internal = git_vector_get(&cfg->files, i); @@ -312,7 +312,7 @@ int git_config_foreach_match( void *payload) { int ret = 0; - unsigned int i; + size_t i; file_internal *internal; git_config_backend *file; -- cgit v1.2.3 From 41954a49c12a72eda3b3fe02c2752f6831b5dbf9 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 18 Mar 2013 14:19:35 -0700 Subject: Switch search paths to classic delimited strings This switches the APIs for setting and getting the global/system search paths from using git_strarray to using a simple string with GIT_PATH_LIST_SEPARATOR delimited paths, just as the environment PATH variable would contain. This makes it simpler to get and set the value. I also added code to expand "$PATH" when setting a new value to embed the old value of the path. This means that I no longer require separate actions to PREPEND to the value. --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index 85db0ab3c..8be5da6b7 100644 --- a/src/config.c +++ b/src/config.c @@ -521,7 +521,7 @@ static int git_config__find_file_to_path( if (path.size >= outlen) { giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path"); - error = -1; + error = GIT_EBUFS; goto done; } -- cgit v1.2.3