summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-03-11 14:25:59 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2014-03-11 14:42:52 +0100
commit2c9c8cdc100bc2e7fdb69eb9d4ad4312cffc460e (patch)
treeaed9aa0816a756f4795b8b9bc6a3b2e3fc6df0dd
parent9af14886a94ca4d08c7af1ba84b21cba40fce34c (diff)
downloadlibgit2-2c9c8cdc100bc2e7fdb69eb9d4ad4312cffc460e.tar.gz
config: let the on-disk backend fail to load gracefully
Failure to read certain paths can be a common misconfiguration on many systems and we do not always want to fail in those cases. Let the on-disk backend fail to load and create an empty one, as could be the case for a privilege-dropping application which does not update its $HOME from the privileged user.
-rw-r--r--include/git2/config.h12
-rw-r--r--src/config.c34
-rw-r--r--src/config.h3
-rw-r--r--src/config_file.c10
-rw-r--r--src/submodule.c2
-rw-r--r--tests/config/new.c21
6 files changed, 66 insertions, 16 deletions
diff --git a/include/git2/config.h b/include/git2/config.h
index 663b4f6ba..87c40519e 100644
--- a/include/git2/config.h
+++ b/include/git2/config.h
@@ -177,6 +177,18 @@ GIT_EXTERN(int) git_config_add_file_ondisk(
int force);
/**
+ * Add an on-disk config file instance to an existing config
+ *
+ * Behaves like git_config_add_file_ondisk but ignores errors when the
+ * path is not accessible.
+ */
+int git_config_add_file_ondisk_gently(
+ git_config *cfg,
+ const char *path,
+ git_config_level_t level,
+ int force);
+
+/**
* Create a new config instance containing a single on-disk file
*
* This method is a simple utility wrapper for the following sequence
diff --git a/src/config.c b/src/config.c
index 1a205fe13..a013ea14c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -86,25 +86,15 @@ int git_config_new(git_config **out)
return 0;
}
-int git_config_add_file_ondisk(
- git_config *cfg,
- const char *path,
- git_config_level_t level,
- int force)
+static int add_file_ondisk(git_config *cfg, const char *path, git_config_level_t level,
+ int force, int allow_fail)
{
git_config_backend *file = NULL;
- struct stat st;
int res;
assert(cfg && path);
- res = p_stat(path, &st);
- if (res < 0 && errno != ENOENT) {
- giterr_set(GITERR_CONFIG, "Error stat'ing config file '%s'", path);
- return -1;
- }
-
- if (git_config_file__ondisk(&file, path) < 0)
+ if (git_config_file__ondisk(&file, path, allow_fail) < 0)
return -1;
if ((res = git_config_add_backend(cfg, file, level, force)) < 0) {
@@ -119,6 +109,24 @@ int git_config_add_file_ondisk(
return 0;
}
+int git_config_add_file_ondisk(
+ git_config *cfg,
+ const char *path,
+ git_config_level_t level,
+ int force)
+{
+ return add_file_ondisk(cfg, path, level, force, 0);
+}
+
+int git_config_add_file_ondisk_gently(
+ git_config *cfg,
+ const char *path,
+ git_config_level_t level,
+ int force)
+{
+ return add_file_ondisk(cfg, path, level, force, 1);
+}
+
int git_config_open_ondisk(git_config **out, const char *path)
{
int error;
diff --git a/src/config.h b/src/config.h
index 03d910616..57ad22a0b 100644
--- a/src/config.h
+++ b/src/config.h
@@ -41,8 +41,9 @@ extern int git_config_rename_section(
*
* @param out the new backend
* @param path where the config file is located
+ * @param allow_fail whether it's ok to fail to open the config file
*/
-extern int git_config_file__ondisk(git_config_backend **out, const char *path);
+extern int git_config_file__ondisk(git_config_backend **out, const char *path, int allow_fail);
extern int git_config__normalize_name(const char *in, char **out);
diff --git a/src/config_file.c b/src/config_file.c
index aedf2cb12..103e6900b 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -96,6 +96,8 @@ typedef struct {
char *file_path;
git_config_level_t level;
+
+ int allow_fail;
} diskfile_backend;
static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth);
@@ -197,6 +199,10 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
/* It's fine if the file doesn't exist */
if (res == GIT_ENOTFOUND)
return 0;
+ /* or if the user doesn't care about failing to open */
+ if (res < 0 && b->allow_fail)
+ return 0;
+
if (res < 0 || (res = config_parse(b, reader, level, 0)) < 0) {
free_vars(b->values);
@@ -608,7 +614,7 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
return result;
}
-int git_config_file__ondisk(git_config_backend **out, const char *path)
+int git_config_file__ondisk(git_config_backend **out, const char *path, int allow_fail)
{
diskfile_backend *backend;
@@ -620,6 +626,8 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
backend->file_path = git__strdup(path);
GITERR_CHECK_ALLOC(backend->file_path);
+ backend->allow_fail = allow_fail;
+
backend->parent.open = config_open;
backend->parent.get = config_get;
backend->parent.set = config_set;
diff --git a/src/submodule.c b/src/submodule.c
index 9eaf77dae..4618587a5 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -1372,7 +1372,7 @@ static git_config_backend *open_gitmodules(
if (okay_to_create || git_path_isfile(path.ptr)) {
/* git_config_file__ondisk should only fail if OOM */
- if (git_config_file__ondisk(&mods, path.ptr) < 0)
+ if (git_config_file__ondisk(&mods, path.ptr, 0) < 0)
mods = NULL;
/* open should only fail here if the file is malformed */
else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL) < 0) {
diff --git a/tests/config/new.c b/tests/config/new.c
index dd6dbca9e..3b38a4817 100644
--- a/tests/config/new.c
+++ b/tests/config/new.c
@@ -30,3 +30,24 @@ void test_config_new__write_new_config(void)
p_unlink(TEST_CONFIG);
}
+
+#define TEST_DIR "perm-dir"
+
+void test_config_new__maybe_fail_on_access(void)
+{
+ git_config *config;
+
+ cl_git_mkfile(TEST_CONFIG, "[core]\nfoo = 4");
+
+ cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
+ git_config_free(config);
+
+ cl_git_pass(p_chmod(TEST_CONFIG, 0000));
+
+ cl_git_fail_with(-1, git_config_open_ondisk(&config, TEST_CONFIG));
+
+ cl_git_pass(git_config_new(&config));
+ cl_git_pass(git_config_add_file_ondisk_gently(config, TEST_CONFIG, 1, 1));
+
+ git_config_free(config);
+}