@matheusbsbs / matheus-bagliano / commits / b09c53a3e3
Fork 0

Sanity-check config variable names

Sanity-check config variable names when adding and retrieving them. As a side effect code duplication between git_config_set_multivar and get_value (in builtin/config.c) was removed and the common functionality was placed in git_config_parse_key. This breaks a test in t1300 which used invalid section-less keys in the tests for "git -c". However, allowing such names there was useless, since there was no way to set them via config file, and no part of git actually tried to use section-less keys. This patch updates the test to use more realistic examples as well as adding its own test. Signed-off-by: Libor Pechacek <lpechacek@suse.cz> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Libor Pechacek committed Jan 30, 2011 at 20:40 UTC b09c53a3e331211fc0154de8ebb271e48f8c7ee5
4 files changed +102 -50
builtin/config.c
+20 -7
@@ -153,7 +153,6 @@ static int show_config(const char *key_, const char *value_, void *cb)
153 static int get_value(const char *key_, const char *regex_)
154 {
155 int ret = -1;
156 - char *tl;
156 char *global = NULL, *repo_config = NULL;
157 const char *system_wide = NULL, *local;
158
@@ -167,18 +166,32 @@ static int get_value(const char *key_, const char *regex_)
166 system_wide = git_etc_gitconfig();
167 }
168
170 - key = xstrdup(key_);
171 - for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
172 - *tl = tolower(*tl);
173 - for (tl=key; *tl && *tl != '.'; ++tl)
174 - *tl = tolower(*tl);
175 -
169 if (use_key_regexp) {
170 + char *tl;
171 +
172 + /*
173 + * NEEDSWORK: this naive pattern lowercasing obviously does not
174 + * work for more complex patterns like "^[^.]*Foo.*bar".
175 + * Perhaps we should deprecate this altogether someday.
176 + */
177 +
178 + key = xstrdup(key_);
179 + for (tl = key + strlen(key) - 1;
180 + tl >= key && *tl != '.';
181 + tl--)
182 + *tl = tolower(*tl);
183 + for (tl = key; *tl && *tl != '.'; tl++)
184 + *tl = tolower(*tl);
185 +
186 key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
187 if (regcomp(key_regexp, key, REG_EXTENDED)) {
188 fprintf(stderr, "Invalid key pattern: %s\n", key_);
189 + free(key);
190 goto free_strings;
191 }
192 + } else {
193 + if (git_config_parse_key(key_, &key, NULL))
194 + goto free_strings;
195 }
196
197 if (regex_) {
cache.h
+1
@@ -997,6 +997,7 @@ extern int git_config_maybe_bool(const char *, const char *);
997 extern int git_config_string(const char **, const char *, const char *);
998 extern int git_config_pathname(const char **, const char *, const char *);
999 extern int git_config_set(const char *, const char *);
1000 +extern int git_config_parse_key(const char *, char **, int *);
1001 extern int git_config_set_multivar(const char *, const char *, const char *, int);
1002 extern int git_config_rename_section(const char *, const char *);
1003 extern const char *git_etc_gitconfig(void);
config.c
+67 -39
@@ -1098,6 +1098,70 @@ int git_config_set(const char *key, const char *value)
1098 return git_config_set_multivar(key, value, NULL, 0);
1099 }
1100
1101 +/*
1102 + * Auxiliary function to sanity-check and split the key into the section
1103 + * identifier and variable name.
1104 + *
1105 + * Returns 0 on success, -1 when there is an invalid character in the key and
1106 + * -2 if there is no section name in the key.
1107 + *
1108 + * store_key - pointer to char* which will hold a copy of the key with
1109 + * lowercase section and variable name
1110 + * baselen - pointer to int which will hold the length of the
1111 + * section + subsection part, can be NULL
1112 + */
1113 +int git_config_parse_key(const char *key, char **store_key, int *baselen_)
1114 +{
1115 + int i, dot, baselen;
1116 + const char *last_dot = strrchr(key, '.');
1117 +
1118 + /*
1119 + * Since "key" actually contains the section name and the real
1120 + * key name separated by a dot, we have to know where the dot is.
1121 + */
1122 +
1123 + if (last_dot == NULL) {
1124 + error("key does not contain a section: %s", key);
1125 + return -2;
1126 + }
1127 +
1128 + baselen = last_dot - key;
1129 + if (baselen_)
1130 + *baselen_ = baselen;
1131 +
1132 + /*
1133 + * Validate the key and while at it, lower case it for matching.
1134 + */
1135 + *store_key = xmalloc(strlen(key) + 1);
1136 +
1137 + dot = 0;
1138 + for (i = 0; key[i]; i++) {
1139 + unsigned char c = key[i];
1140 + if (c == '.')
1141 + dot = 1;
1142 + /* Leave the extended basename untouched.. */
1143 + if (!dot || i > baselen) {
1144 + if (!iskeychar(c) ||
1145 + (i == baselen + 1 && !isalpha(c))) {
1146 + error("invalid key: %s", key);
1147 + goto out_free_ret_1;
1148 + }
1149 + c = tolower(c);
1150 + } else if (c == '\n') {
1151 + error("invalid key (newline): %s", key);
1152 + goto out_free_ret_1;
1153 + }
1154 + (*store_key)[i] = c;
1155 + }
1156 + (*store_key)[i] = 0;
1157 +
1158 + return 0;
1159 +
1160 +out_free_ret_1:
1161 + free(*store_key);
1162 + return -1;
1163 +}
1164 +
1165 /*
1166 * If value==NULL, unset in (remove from) config,
1167 * if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1124,59 +1188,23 @@ int git_config_set(const char *key, const char *value)
1188 int git_config_set_multivar(const char *key, const char *value,
1189 const char *value_regex, int multi_replace)
1190 {
1127 - int i, dot;
1191 int fd = -1, in_fd;
1192 int ret;
1193 char *config_filename;
1194 struct lock_file *lock = NULL;
1132 - const char *last_dot = strrchr(key, '.');
1195
1196 if (config_exclusive_filename)
1197 config_filename = xstrdup(config_exclusive_filename);
1198 else
1199 config_filename = git_pathdup("config");
1200
1139 - /*
1140 - * Since "key" actually contains the section name and the real
1141 - * key name separated by a dot, we have to know where the dot is.
1142 - */
1143 -
1144 - if (last_dot == NULL) {
1145 - error("key does not contain a section: %s", key);
1146 - ret = 2;
1201 + /* parse-key returns negative; flip the sign to feed exit(3) */
1202 + ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
1203 + if (ret)
1204 goto out_free;
1148 - }
1149 - store.baselen = last_dot - key;
1205
1206 store.multi_replace = multi_replace;
1207
1153 - /*
1154 - * Validate the key and while at it, lower case it for matching.
1155 - */
1156 - store.key = xmalloc(strlen(key) + 1);
1157 - dot = 0;
1158 - for (i = 0; key[i]; i++) {
1159 - unsigned char c = key[i];
1160 - if (c == '.')
1161 - dot = 1;
1162 - /* Leave the extended basename untouched.. */
1163 - if (!dot || i > store.baselen) {
1164 - if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
1165 - error("invalid key: %s", key);
1166 - free(store.key);
1167 - ret = 1;
1168 - goto out_free;
1169 - }
1170 - c = tolower(c);
1171 - } else if (c == '\n') {
1172 - error("invalid key (newline): %s", key);
1173 - free(store.key);
1174 - ret = 1;
1175 - goto out_free;
1176 - }
1177 - store.key[i] = c;
1178 - }
1179 - store.key[i] = 0;
1208
1209 /*
1210 * The lock serves a purpose in addition to locking: the new
t/t1300-repo-config.sh
+14 -4
@@ -876,11 +876,21 @@ test_expect_success 'check split_cmdline return' "
876 "
877
878 test_expect_success 'git -c "key=value" support' '
879 - test "z$(git -c name=value config name)" = zvalue &&
879 test "z$(git -c core.name=value config core.name)" = zvalue &&
881 - test "z$(git -c CamelCase=value config camelcase)" = zvalue &&
882 - test "z$(git -c flag config --bool flag)" = ztrue &&
883 - test_must_fail git -c core.name=value config name
880 + test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue &&
881 + test "z$(git -c foo.flag config --bool foo.flag)" = ztrue &&
882 + test_must_fail git -c name=value config core.name
883 +'
884 +
885 +test_expect_success 'key sanity-checking' '
886 + test_must_fail git config foo=bar &&
887 + test_must_fail git config foo=.bar &&
888 + test_must_fail git config foo.ba=r &&
889 + test_must_fail git config foo.1bar &&
890 + test_must_fail git config foo."ba
891 + z".bar &&
892 + git config foo.bar true &&
893 + git config foo."ba =z".bar false
894 '
895
896 test_done