git-config: always treat --int as 64-bit internally
authorJeff King <peff@peff.net>
Sun, 8 Sep 2013 08:40:02 +0000 (04:40 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2013 18:12:29 +0000 (11:12 -0700)
When you run "git config --int", the maximum size of integer
you get depends on how git was compiled, and what it
considers to be an "int".

This is almost useful, because your scripts calling "git
config" will behave similarly to git internally. But relying
on this is dubious; you have to actually know how git treats
each value internally (e.g., int versus unsigned long),
which is not documented and is subject to change. And even
if you know it is "unsigned long", we do not have a
git-config option to match that behavior.

Furthermore, you may simply be asking git to store a value
on your behalf (e.g., configuration for a hook). In that
case, the relevant range check has nothing at all to do with
git, but rather with whatever scripting tools you are using
(and git has no way of knowing what the appropriate range is
there).

Not only is the range check useless, but it is actively
harmful, as there is no way at all for scripts to look
at config variables with large values. For instance, one
cannot reliably get the value of pack.packSizeLimit via
git-config. On an LP64 system, git happily uses a 64-bit
"unsigned long" internally to represent the value, but the
script cannot read any value over 2G.

Ideally, the "--int" option would simply represent an
arbitrarily large integer. For practical purposes, however,
a 64-bit integer is large enough, and is much easier to
implement (and if somebody overflows it, we will still
notice the problem, and not simply return garbage).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/config.c
cache.h
config.c
t/t1300-repo-config.sh
index 4010c4320a585d84bdb0914d8a9bbc27d38b7f18..8b182d2a9f281605fa0e53c1e39972020e64b557 100644 (file)
@@ -128,7 +128,8 @@ static int collect_config(const char *key_, const char *value_, void *cb)
                must_print_delim = 1;
        }
        if (types == TYPE_INT)
-               sprintf(value, "%d", git_config_int(key_, value_?value_:""));
+               sprintf(value, "%"PRId64,
+                       git_config_int64(key_, value_ ? value_ : ""));
        else if (types == TYPE_BOOL)
                vptr = git_config_bool(key_, value_) ? "true" : "false";
        else if (types == TYPE_BOOL_OR_INT) {
@@ -265,8 +266,8 @@ static char *normalize_value(const char *key, const char *value)
        else {
                normalized = xmalloc(64);
                if (types == TYPE_INT) {
-                       int v = git_config_int(key, value);
-                       sprintf(normalized, "%d", v);
+                       int64_t v = git_config_int64(key, value);
+                       sprintf(normalized, "%"PRId64, v);
                }
                else if (types == TYPE_BOOL)
                        sprintf(normalized, "%s",
diff --git a/cache.h b/cache.h
index 85b544f38d934fe68d1e155c86337f1400eea14d..ac4525aabb72eb3ad40baaf900b0353defaa30b8 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1190,6 +1190,7 @@ extern int git_config_with_options(config_fn_t fn, void *,
 extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_config_int(const char *, const char *);
+extern int64_t git_config_int64(const char *, const char *);
 extern unsigned long git_config_ulong(const char *, const char *);
 extern int git_config_bool_or_int(const char *, const char *, int *);
 extern int git_config_bool(const char *, const char *);
index 4be6c7ba2bc0b48de4e465ad2f4c26bd114c3729..3ffe134c57f6076aeb13761ea2e741cb1df40dd1 100644 (file)
--- a/config.c
+++ b/config.c
@@ -534,6 +534,15 @@ static int git_parse_int(const char *value, int *ret)
        return 1;
 }
 
+static int git_parse_int64(const char *value, int64_t *ret)
+{
+       intmax_t tmp;
+       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
 int git_parse_ulong(const char *value, unsigned long *ret)
 {
        uintmax_t tmp;
@@ -565,6 +574,14 @@ int git_config_int(const char *name, const char *value)
        return ret;
 }
 
+int64_t git_config_int64(const char *name, const char *value)
+{
+       int64_t ret;
+       if (!git_parse_int64(value, &ret))
+               die_bad_number(name, value);
+       return ret;
+}
+
 unsigned long git_config_ulong(const char *name, const char *value)
 {
        unsigned long ret;
index 20aee6e171c41139007187d6155339d484f44d54..b66c63262162e54377f975ac153d448ae05557d1 100755 (executable)
@@ -652,6 +652,13 @@ test_expect_success numbers '
        test_cmp expect actual
 '
 
+test_expect_success '--int is at least 64 bits' '
+       git config giga.watts 121g &&
+       echo 129922760704 >expect &&
+       git config --int --get giga.watts >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'invalid unit' '
        git config aninvalid.unit "1auto" &&
        echo 1auto >expect &&