]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fast-import: add new --date-format=raw-permissive format
authorElijah Newren <newren@gmail.com>
Sat, 30 May 2020 20:25:57 +0000 (20:25 +0000)
committerJunio C Hamano <gitster@pobox.com>
Sun, 31 May 2020 16:03:10 +0000 (09:03 -0700)
There are multiple repositories in the wild with random, invalid
timezones.  Most notably is a commit from rails.git with a timezone of
"+051800"[1].  A few searches will find other repos with that same
invalid timezone as well.  Further, Peff reports that GitHub relaxed
their fsck checks in August 2011 to accept any timezone value[2], and
there have been multiple reports to filter-repo about fast-import
crashing while trying to import their existing repositories since they
had timezone values such as "-7349423" and "-43455309"[3].

The existing check on timezone values inside fast-import may prove
useful for people who are crafting fast-import input by hand or with a
new script.  For them, the check may help them avoid accidentally
recording invalid dates.  (Note that this check is rather simplistic and
there are still several forms of invalid dates that fast-import does not
check for: dates in the future, timezone values with minutes that are
not divisible by 15, and timezone values with minutes that are 60 or
greater.)  While this simple check may have some value for those users,
other users or tools will want to import existing repositories as-is.
Provide a --date-format=raw-permissive format that will not error out on
these otherwise invalid timezones so that such existing repositories can
be imported.

[1] https://github.com/rails/rails/commit/4cf94979c9f4d6683c9338d694d5eb3106a4e734
[2] https://lore.kernel.org/git/20200521195513.GA1542632@coredump.intra.peff.net/
[3] https://github.com/newren/git-filter-repo/issues/88

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-fast-import.txt
fast-import.c
t/t9300-fast-import.sh

index 7889f95940544a016c5ddf696f0995177f5b36e6..9a2aaf1e74a8545c059488bef9bbbef8215ca638 100644 (file)
@@ -273,7 +273,14 @@ by users who are located in the same location and time zone.  In this
 case a reasonable offset from UTC could be assumed.
 +
 Unlike the `rfc2822` format, this format is very strict.  Any
-variation in formatting will cause fast-import to reject the value.
+variation in formatting will cause fast-import to reject the value,
+and some sanity checks on the numeric values may also be performed.
+
+`raw-permissive`::
+       This is the same as `raw` except that no sanity checks on
+       the numeric epoch and local offset are performed.  This can
+       be useful when trying to filter or import an existing history
+       with e.g. bogus timezone values.
 
 `rfc2822`::
        This is the standard email format as described by RFC 2822.
index b8b65a801cc1f902f7131590816459d2d1e0faa0..929793ba149a9d43072e730a5c705296380dcdf5 100644 (file)
@@ -121,6 +121,7 @@ struct hash_list {
 
 typedef enum {
        WHENSPEC_RAW = 1,
+       WHENSPEC_RAW_PERMISSIVE,
        WHENSPEC_RFC2822,
        WHENSPEC_NOW
 } whenspec_type;
@@ -1874,7 +1875,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
        return 1;
 }
 
-static int validate_raw_date(const char *src, struct strbuf *result)
+static int validate_raw_date(const char *src, struct strbuf *result, int strict)
 {
        const char *orig_src = src;
        char *endp;
@@ -1883,7 +1884,11 @@ static int validate_raw_date(const char *src, struct strbuf *result)
        errno = 0;
 
        num = strtoul(src, &endp, 10);
-       /* NEEDSWORK: perhaps check for reasonable values? */
+       /*
+        * NEEDSWORK: perhaps check for reasonable values? For example, we
+        *            could error on values representing times more than a
+        *            day in the future.
+        */
        if (errno || endp == src || *endp != ' ')
                return -1;
 
@@ -1892,7 +1897,13 @@ static int validate_raw_date(const char *src, struct strbuf *result)
                return -1;
 
        num = strtoul(src + 1, &endp, 10);
-       if (errno || endp == src + 1 || *endp || 1400 < num)
+       /*
+        * NEEDSWORK: check for brokenness other than num > 1400, such as
+        *            (num % 100) >= 60, or ((num % 100) % 15) != 0 ?
+        */
+       if (errno || endp == src + 1 || *endp || /* did not parse */
+           (strict && (1400 < num))             /* parsed a broken timezone */
+          )
                return -1;
 
        strbuf_addstr(result, orig_src);
@@ -1926,7 +1937,11 @@ static char *parse_ident(const char *buf)
 
        switch (whenspec) {
        case WHENSPEC_RAW:
-               if (validate_raw_date(ltgt, &ident) < 0)
+               if (validate_raw_date(ltgt, &ident, 1) < 0)
+                       die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
+               break;
+       case WHENSPEC_RAW_PERMISSIVE:
+               if (validate_raw_date(ltgt, &ident, 0) < 0)
                        die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
                break;
        case WHENSPEC_RFC2822:
@@ -3161,6 +3176,8 @@ static void option_date_format(const char *fmt)
 {
        if (!strcmp(fmt, "raw"))
                whenspec = WHENSPEC_RAW;
+       else if (!strcmp(fmt, "raw-permissive"))
+               whenspec = WHENSPEC_RAW_PERMISSIVE;
        else if (!strcmp(fmt, "rfc2822"))
                whenspec = WHENSPEC_RFC2822;
        else if (!strcmp(fmt, "now"))
index 3e41c58a13689b65bf5a9ed6b2fc6466b303af81..af807abe3275d50e692aa21be407c8e4e66b5583 100755 (executable)
@@ -410,6 +410,34 @@ test_expect_success 'B: accept empty committer' '
        test -z "$out"
 '
 
+test_expect_success 'B: reject invalid timezone' '
+       cat >input <<-INPUT_END &&
+       commit refs/heads/invalid-timezone
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1234567890 +051800
+       data <<COMMIT
+       empty commit
+       COMMIT
+       INPUT_END
+
+       test_when_finished "git update-ref -d refs/heads/invalid-timezone" &&
+       test_must_fail git fast-import <input
+'
+
+test_expect_success 'B: accept invalid timezone with raw-permissive' '
+       cat >input <<-INPUT_END &&
+       commit refs/heads/invalid-timezone
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1234567890 +051800
+       data <<COMMIT
+       empty commit
+       COMMIT
+       INPUT_END
+
+       git init invalid-timezone &&
+       git -C invalid-timezone fast-import --date-format=raw-permissive <input &&
+       git -C invalid-timezone cat-file -p invalid-timezone >out &&
+       grep "1234567890 [+]051800" out
+'
+
 test_expect_success 'B: accept and fixup committer with no name' '
        cat >input <<-INPUT_END &&
        commit refs/heads/empty-committer-2