mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-09 22:27:57 +00:00
Merge pull request #758 from libgit2/config-values-containing-quotes
Quotes inside config values don't survive serialization/deserialization
This commit is contained in:
commit
68f527c448
@ -87,6 +87,7 @@ typedef struct {
|
|||||||
static int config_parse(diskfile_backend *cfg_file);
|
static int config_parse(diskfile_backend *cfg_file);
|
||||||
static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value);
|
static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value);
|
||||||
static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value);
|
static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value);
|
||||||
|
static char *escape_value(const char *ptr);
|
||||||
|
|
||||||
static void set_parse_error(diskfile_backend *backend, int col, const char *error_str)
|
static void set_parse_error(diskfile_backend *backend, int col, const char *error_str)
|
||||||
{
|
{
|
||||||
@ -212,9 +213,9 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
|||||||
{
|
{
|
||||||
cvar_t *var = NULL, *old_var;
|
cvar_t *var = NULL, *old_var;
|
||||||
diskfile_backend *b = (diskfile_backend *)cfg;
|
diskfile_backend *b = (diskfile_backend *)cfg;
|
||||||
char *key;
|
char *key, *esc_value = NULL;
|
||||||
khiter_t pos;
|
khiter_t pos;
|
||||||
int rval;
|
int rval, ret;
|
||||||
|
|
||||||
if (normalize_name(name, &key) < 0)
|
if (normalize_name(name, &key) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -237,12 +238,17 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
|||||||
if (value) {
|
if (value) {
|
||||||
tmp = git__strdup(value);
|
tmp = git__strdup(value);
|
||||||
GITERR_CHECK_ALLOC(tmp);
|
GITERR_CHECK_ALLOC(tmp);
|
||||||
|
esc_value = escape_value(value);
|
||||||
|
GITERR_CHECK_ALLOC(esc_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
git__free(existing->value);
|
git__free(existing->value);
|
||||||
existing->value = tmp;
|
existing->value = tmp;
|
||||||
|
|
||||||
return config_write(b, existing->key, NULL, value);
|
ret = config_write(b, existing->key, NULL, esc_value);
|
||||||
|
|
||||||
|
git__free(esc_value);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
var = git__malloc(sizeof(cvar_t));
|
var = git__malloc(sizeof(cvar_t));
|
||||||
@ -256,13 +262,17 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
|||||||
if (value) {
|
if (value) {
|
||||||
var->value = git__strdup(value);
|
var->value = git__strdup(value);
|
||||||
GITERR_CHECK_ALLOC(var->value);
|
GITERR_CHECK_ALLOC(var->value);
|
||||||
|
esc_value = escape_value(value);
|
||||||
|
GITERR_CHECK_ALLOC(esc_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_write(b, key, NULL, value) < 0) {
|
if (config_write(b, key, NULL, esc_value) < 0) {
|
||||||
|
git__free(esc_value);
|
||||||
cvar_free(var);
|
cvar_free(var);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
git__free(esc_value);
|
||||||
git_strmap_insert2(b->values, key, var, old_var, rval);
|
git_strmap_insert2(b->values, key, var, old_var, rval);
|
||||||
if (rval < 0)
|
if (rval < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -1155,13 +1165,44 @@ rewrite_fail:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *escapes = "ntb\"\\";
|
||||||
|
static const char *escaped = "\n\t\b\"\\";
|
||||||
|
|
||||||
|
/* Escape the values to write them to the file */
|
||||||
|
static char *escape_value(const char *ptr)
|
||||||
|
{
|
||||||
|
git_buf buf = GIT_BUF_INIT;
|
||||||
|
size_t len;
|
||||||
|
const char *esc;
|
||||||
|
|
||||||
|
assert(ptr);
|
||||||
|
|
||||||
|
len = strlen(ptr);
|
||||||
|
git_buf_grow(&buf, len);
|
||||||
|
|
||||||
|
while (*ptr != '\0') {
|
||||||
|
if ((esc = strchr(escaped, *ptr)) != NULL) {
|
||||||
|
git_buf_putc(&buf, '\\');
|
||||||
|
git_buf_putc(&buf, escapes[esc - escaped]);
|
||||||
|
} else {
|
||||||
|
git_buf_putc(&buf, *ptr);
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git_buf_oom(&buf)) {
|
||||||
|
git_buf_free(&buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return git_buf_detach(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
/* '\"' -> '"' etc */
|
/* '\"' -> '"' etc */
|
||||||
static char *fixup_line(const char *ptr, int quote_count)
|
static char *fixup_line(const char *ptr, int quote_count)
|
||||||
{
|
{
|
||||||
char *str = git__malloc(strlen(ptr) + 1);
|
char *str = git__malloc(strlen(ptr) + 1);
|
||||||
char *out = str, *esc;
|
char *out = str, *esc;
|
||||||
const char *escapes = "ntb\"\\";
|
|
||||||
const char *escaped = "\n\t\b\"\\";
|
|
||||||
|
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -90,3 +90,49 @@ void test_config_write__delete_inexistent(void)
|
|||||||
cl_assert(git_config_delete(cfg, "core.imaginary") == GIT_ENOTFOUND);
|
cl_assert(git_config_delete(cfg, "core.imaginary") == GIT_ENOTFOUND);
|
||||||
git_config_free(cfg);
|
git_config_free(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_config_write__value_containing_quotes(void)
|
||||||
|
{
|
||||||
|
git_config *cfg;
|
||||||
|
const char* str;
|
||||||
|
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
|
||||||
|
cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes"));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, "core.somevar"));
|
||||||
|
cl_assert_equal_s(str, "this \"has\" quotes");
|
||||||
|
git_config_free(cfg);
|
||||||
|
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, "core.somevar"));
|
||||||
|
cl_assert_equal_s(str, "this \"has\" quotes");
|
||||||
|
git_config_free(cfg);
|
||||||
|
|
||||||
|
/* The code path for values that already exist is different, check that one as well */
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
|
||||||
|
cl_git_pass(git_config_set_string(cfg, "core.somevar", "this also \"has\" quotes"));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, "core.somevar"));
|
||||||
|
cl_assert_equal_s(str, "this also \"has\" quotes");
|
||||||
|
git_config_free(cfg);
|
||||||
|
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, "core.somevar"));
|
||||||
|
cl_assert_equal_s(str, "this also \"has\" quotes");
|
||||||
|
git_config_free(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_config_write__escape_value(void)
|
||||||
|
{
|
||||||
|
git_config *cfg;
|
||||||
|
const char* str;
|
||||||
|
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
|
||||||
|
cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes and \t"));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, "core.somevar"));
|
||||||
|
cl_assert_equal_s(str, "this \"has\" quotes and \t");
|
||||||
|
git_config_free(cfg);
|
||||||
|
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, "core.somevar"));
|
||||||
|
cl_assert_equal_s(str, "this \"has\" quotes and \t");
|
||||||
|
git_config_free(cfg);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user