Merge branch 'lp/config-vername-check' into maint
authorJunio C Hamano <gitster@pobox.com>
Sun, 3 Apr 2011 19:29:45 +0000 (12:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 3 Apr 2011 19:29:45 +0000 (12:29 -0700)
* lp/config-vername-check:
Disallow empty section and variable names
Sanity-check config variable names

1  2 
builtin/config.c
cache.h
config.c
diff --combined builtin/config.c
index b8b18e3c94b5730afb343089821e8e622a5b00ee,6754da8f5e9df0156f0ac32b10724202b893a7fd..f87443698a2b572e0d6d5e322905d78a907c8b86
@@@ -52,7 -52,7 +52,7 @@@ static struct option builtin_config_opt
        OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
        OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
        OPT_BOOLEAN(0, "local", &use_local_config, "use repository config file"),
 -      OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"),
 +      OPT_STRING('f', "file", &given_config_file, "file", "use given config file"),
        OPT_GROUP("Action"),
        OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
        OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
@@@ -153,7 -153,6 +153,6 @@@ static int show_config(const char *key_
  static int get_value(const char *key_, const char *regex_)
  {
        int ret = -1;
-       char *tl;
        char *global = NULL, *repo_config = NULL;
        const char *system_wide = NULL, *local;
  
                        system_wide = git_etc_gitconfig();
        }
  
-       key = xstrdup(key_);
-       for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
-               *tl = tolower(*tl);
-       for (tl=key; *tl && *tl != '.'; ++tl)
-               *tl = tolower(*tl);
        if (use_key_regexp) {
+               char *tl;
+               /*
+                * NEEDSWORK: this naive pattern lowercasing obviously does not
+                * work for more complex patterns like "^[^.]*Foo.*bar".
+                * Perhaps we should deprecate this altogether someday.
+                */
+               key = xstrdup(key_);
+               for (tl = key + strlen(key) - 1;
+                    tl >= key && *tl != '.';
+                    tl--)
+                       *tl = tolower(*tl);
+               for (tl = key; *tl && *tl != '.'; tl++)
+                       *tl = tolower(*tl);
                key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
+                       free(key);
                        goto free_strings;
                }
+       } else {
+               if (git_config_parse_key(key_, &key, NULL))
+                       goto free_strings;
        }
  
        if (regex_) {
diff --combined cache.h
index f2dabefd9d75fddf0eb48e42a0907db6ac162b08,1e32d63fb585a0fd45e2512f6f74726130510f06..e637ca8e01a4a42044e217f4d2bcecabbee7c3b1
+++ b/cache.h
@@@ -545,6 -545,7 +545,6 @@@ extern int assume_unchanged
  extern int prefer_symlink_refs;
  extern int log_all_ref_updates;
  extern int warn_ambiguous_refs;
 -extern int unique_abbrev_extra_length;
  extern int shared_repository;
  extern const char *apply_default_whitespace;
  extern const char *apply_default_ignorewhitespace;
@@@ -570,7 -571,7 +570,7 @@@ extern enum safe_crlf safe_crlf
  enum auto_crlf {
        AUTO_CRLF_FALSE = 0,
        AUTO_CRLF_TRUE = 1,
 -      AUTO_CRLF_INPUT = -1,
 +      AUTO_CRLF_INPUT = -1
  };
  
  extern enum auto_crlf auto_crlf;
@@@ -607,7 -608,7 +607,7 @@@ enum rebase_setup_type 
  enum push_default_type {
        PUSH_DEFAULT_NOTHING = 0,
        PUSH_DEFAULT_MATCHING,
 -      PUSH_DEFAULT_TRACKING,
 +      PUSH_DEFAULT_UPSTREAM,
        PUSH_DEFAULT_CURRENT
  };
  
@@@ -675,11 -676,9 +675,11 @@@ static inline void hashclr(unsigned cha
  
  #define EMPTY_TREE_SHA1_HEX \
        "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
 -#define EMPTY_TREE_SHA1_BIN \
 +#define EMPTY_TREE_SHA1_BIN_LITERAL \
         "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
         "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
 +#define EMPTY_TREE_SHA1_BIN \
 +       ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
  
  int git_mkstemp(char *path, size_t n, const char *template);
  
@@@ -898,8 -897,7 +898,8 @@@ extern struct packed_git 
        time_t mtime;
        int pack_fd;
        unsigned pack_local:1,
 -               pack_keep:1;
 +               pack_keep:1,
 +               do_not_close:1;
        unsigned char sha1[20];
        /* something like ".git/objects/pack/xxxxx.pack" */
        char pack_name[FLEX_ARRAY]; /* more */
@@@ -999,6 -997,7 +999,7 @@@ extern int git_config_maybe_bool(const 
  extern int git_config_string(const char **, const char *, const char *);
  extern int git_config_pathname(const char **, const char *, const char *);
  extern int git_config_set(const char *, const char *);
+ extern int git_config_parse_key(const char *, char **, int *);
  extern int git_config_set_multivar(const char *, const char *, const char *, int);
  extern int git_config_rename_section(const char *, const char *);
  extern const char *git_etc_gitconfig(void);
diff --combined config.c
index 822ef8365ce29c48e4b04fcccc47ba2e0b3a255f,d5bb8629a9bbad0c78d51b1466f257ad1c64dbac..fa740a6a60a49512b613f70add97d445f622afd2
+++ b/config.c
@@@ -20,7 -20,8 +20,7 @@@ static int zlib_compression_seen
  
  const char *config_exclusive_filename = NULL;
  
 -struct config_item
 -{
 +struct config_item {
        struct config_item *next;
        char *name;
        char *value;
@@@ -498,6 -499,13 +498,6 @@@ static int git_default_core_config(cons
                return 0;
        }
  
 -      if (!strcmp(var, "core.abbrevguard")) {
 -              unique_abbrev_extra_length = git_config_int(var, value);
 -              if (unique_abbrev_extra_length < 0)
 -                      unique_abbrev_extra_length = 0;
 -              return 0;
 -      }
 -
        if (!strcmp(var, "core.bare")) {
                is_bare_repository_cfg = git_config_bool(var, value);
                return 0;
@@@ -729,10 -737,8 +729,10 @@@ static int git_default_push_config(cons
                        push_default = PUSH_DEFAULT_NOTHING;
                else if (!strcmp(value, "matching"))
                        push_default = PUSH_DEFAULT_MATCHING;
 -              else if (!strcmp(value, "tracking"))
 -                      push_default = PUSH_DEFAULT_TRACKING;
 +              else if (!strcmp(value, "upstream"))
 +                      push_default = PUSH_DEFAULT_UPSTREAM;
 +              else if (!strcmp(value, "tracking")) /* deprecated */
 +                      push_default = PUSH_DEFAULT_UPSTREAM;
                else if (!strcmp(value, "current"))
                        push_default = PUSH_DEFAULT_CURRENT;
                else {
@@@ -1092,6 -1098,75 +1092,75 @@@ int git_config_set(const char *key, con
        return git_config_set_multivar(key, value, NULL, 0);
  }
  
+ /*
+  * Auxiliary function to sanity-check and split the key into the section
+  * identifier and variable name.
+  *
+  * Returns 0 on success, -1 when there is an invalid character in the key and
+  * -2 if there is no section name in the key.
+  *
+  * store_key - pointer to char* which will hold a copy of the key with
+  *             lowercase section and variable name
+  * baselen - pointer to int which will hold the length of the
+  *           section + subsection part, can be NULL
+  */
+ int git_config_parse_key(const char *key, char **store_key, int *baselen_)
+ {
+       int i, dot, baselen;
+       const char *last_dot = strrchr(key, '.');
+       /*
+        * Since "key" actually contains the section name and the real
+        * key name separated by a dot, we have to know where the dot is.
+        */
+       if (last_dot == NULL || last_dot == key) {
+               error("key does not contain a section: %s", key);
+               return -2;
+       }
+       if (!last_dot[1]) {
+               error("key does not contain variable name: %s", key);
+               return -2;
+       }
+       baselen = last_dot - key;
+       if (baselen_)
+               *baselen_ = baselen;
+       /*
+        * Validate the key and while at it, lower case it for matching.
+        */
+       *store_key = xmalloc(strlen(key) + 1);
+       dot = 0;
+       for (i = 0; key[i]; i++) {
+               unsigned char c = key[i];
+               if (c == '.')
+                       dot = 1;
+               /* Leave the extended basename untouched.. */
+               if (!dot || i > baselen) {
+                       if (!iskeychar(c) ||
+                           (i == baselen + 1 && !isalpha(c))) {
+                               error("invalid key: %s", key);
+                               goto out_free_ret_1;
+                       }
+                       c = tolower(c);
+               } else if (c == '\n') {
+                       error("invalid key (newline): %s", key);
+                       goto out_free_ret_1;
+               }
+               (*store_key)[i] = c;
+       }
+       (*store_key)[i] = 0;
+       return 0;
+ out_free_ret_1:
+       free(*store_key);
+       return -1;
+ }
  /*
   * If value==NULL, unset in (remove from) config,
   * if value_regex!=NULL, disregard key/value pairs where value does not match.
  int git_config_set_multivar(const char *key, const char *value,
        const char *value_regex, int multi_replace)
  {
-       int i, dot;
        int fd = -1, in_fd;
        int ret;
        char *config_filename;
        struct lock_file *lock = NULL;
-       const char *last_dot = strrchr(key, '.');
  
        if (config_exclusive_filename)
                config_filename = xstrdup(config_exclusive_filename);
        else
                config_filename = git_pathdup("config");
  
-       /*
-        * Since "key" actually contains the section name and the real
-        * key name separated by a dot, we have to know where the dot is.
-        */
-       if (last_dot == NULL) {
-               error("key does not contain a section: %s", key);
-               ret = 2;
+       /* parse-key returns negative; flip the sign to feed exit(3) */
+       ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
+       if (ret)
                goto out_free;
-       }
-       store.baselen = last_dot - key;
  
        store.multi_replace = multi_replace;
  
-       /*
-        * Validate the key and while at it, lower case it for matching.
-        */
-       store.key = xmalloc(strlen(key) + 1);
-       dot = 0;
-       for (i = 0; key[i]; i++) {
-               unsigned char c = key[i];
-               if (c == '.')
-                       dot = 1;
-               /* Leave the extended basename untouched.. */
-               if (!dot || i > store.baselen) {
-                       if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
-                               error("invalid key: %s", key);
-                               free(store.key);
-                               ret = 1;
-                               goto out_free;
-                       }
-                       c = tolower(c);
-               } else if (c == '\n') {
-                       error("invalid key (newline): %s", key);
-                       free(store.key);
-                       ret = 1;
-                       goto out_free;
-               }
-               store.key[i] = c;
-       }
-       store.key[i] = 0;
  
        /*
         * The lock serves a purpose in addition to locking: the new