Merge branch 'maint-2.0' into maint-2.1
authorJunio C Hamano <gitster@pobox.com>
Wed, 7 Jan 2015 21:27:56 +0000 (13:27 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 7 Jan 2015 21:27:56 +0000 (13:27 -0800)
* maint-2.0:
  is_hfs_dotgit: loosen over-eager match of \u{..47}

1  2 
t/t1450-fsck.sh
utf8.c

diff --combined t/t1450-fsck.sh
@@@ -69,7 -69,7 +69,7 @@@ test_expect_success 'object with bad sh
        git update-ref refs/heads/bogus $cmt &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
  
 -      test_might_fail git fsck 2>out &&
 +      test_must_fail git fsck 2>out &&
        cat out &&
        grep "$sha.*corrupt" out
  '
@@@ -101,7 -101,7 +101,7 @@@ test_expect_success 'email with embedde
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
 -      git fsck 2>out &&
 +      test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new" out
  '
@@@ -113,7 -113,7 +113,7 @@@ test_expect_success 'missing < email de
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
 -      git fsck 2>out &&
 +      test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new.* - bad name" out
  '
@@@ -125,7 -125,7 +125,7 @@@ test_expect_success 'missing email is r
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
 -      git fsck 2>out &&
 +      test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new.* - missing email" out
  '
@@@ -137,7 -137,7 +137,7 @@@ test_expect_success '> in name is repor
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
 -      git fsck 2>out &&
 +      test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new" out
  '
@@@ -151,31 -151,11 +151,31 @@@ test_expect_success 'integer overflow i
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
 -      git fsck 2>out &&
 +      test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new.*integer overflow" out
  '
  
 +test_expect_success 'malformatted tree object' '
 +      test_when_finished "git update-ref -d refs/tags/wrong" &&
 +      test_when_finished "remove_object \$T" &&
 +      T=$(
 +              GIT_INDEX_FILE=test-index &&
 +              export GIT_INDEX_FILE &&
 +              rm -f test-index &&
 +              >x &&
 +              git add x &&
 +              T=$(git write-tree) &&
 +              (
 +                      git cat-file tree $T &&
 +                      git cat-file tree $T
 +              ) |
 +              git hash-object -w -t tree --stdin
 +      ) &&
 +      test_must_fail git fsck 2>out &&
 +      grep "error in tree .*contains duplicate file entries" out
 +'
 +
  test_expect_success 'tag pointing to nonexistent' '
        cat >invalid-tag <<-\EOF &&
        object ffffffffffffffffffffffffffffffffffffffff
@@@ -307,60 -287,19 +307,75 @@@ dot-backslash-case .\\\\.GIT\\\\fooba
  dotgit-case-backslash .git\\\\foobar
  EOF
  
+ test_expect_success 'fsck allows .Ňit' '
+       (
+               git init not-dotgit &&
+               cd not-dotgit &&
+               echo content >file &&
+               git add file &&
+               git commit -m base &&
+               blob=$(git rev-parse :file) &&
+               printf "100644 blob $blob\t.\\305\\207it" >tree &&
+               tree=$(git mktree <tree) &&
+               git fsck 2>err &&
+               test_line_count = 0 err
+       )
+ '
 +# create a static test repo which is broken by omitting
 +# one particular object ($1, which is looked up via rev-parse
 +# in the new repository).
 +create_repo_missing () {
 +      rm -rf missing &&
 +      git init missing &&
 +      (
 +              cd missing &&
 +              git commit -m one --allow-empty &&
 +              mkdir subdir &&
 +              echo content >subdir/file &&
 +              git add subdir/file &&
 +              git commit -m two &&
 +              unrelated=$(echo unrelated | git hash-object --stdin -w) &&
 +              git tag -m foo tag $unrelated &&
 +              sha1=$(git rev-parse --verify "$1") &&
 +              path=$(echo $sha1 | sed 's|..|&/|') &&
 +              rm .git/objects/$path
 +      )
 +}
 +
 +test_expect_success 'fsck notices missing blob' '
 +      create_repo_missing HEAD:subdir/file &&
 +      test_must_fail git -C missing fsck
 +'
 +
 +test_expect_success 'fsck notices missing subtree' '
 +      create_repo_missing HEAD:subdir &&
 +      test_must_fail git -C missing fsck
 +'
 +
 +test_expect_success 'fsck notices missing root tree' '
 +      create_repo_missing HEAD^{tree} &&
 +      test_must_fail git -C missing fsck
 +'
 +
 +test_expect_success 'fsck notices missing parent' '
 +      create_repo_missing HEAD^ &&
 +      test_must_fail git -C missing fsck
 +'
 +
 +test_expect_success 'fsck notices missing tagged object' '
 +      create_repo_missing tag^{blob} &&
 +      test_must_fail git -C missing fsck
 +'
 +
 +test_expect_success 'fsck notices ref pointing to missing commit' '
 +      create_repo_missing HEAD &&
 +      test_must_fail git -C missing fsck
 +'
 +
 +test_expect_success 'fsck notices ref pointing to missing tag' '
 +      create_repo_missing tag &&
 +      test_must_fail git -C missing fsck
 +'
 +
  test_done
diff --combined utf8.c
--- 1/utf8.c
--- 2/utf8.c
+++ b/utf8.c
@@@ -80,8 -80,52 +80,8 @@@ static int git_wcwidth(ucs_char_t ch
  {
        /*
         * Sorted list of non-overlapping intervals of non-spacing characters,
 -       * generated by
 -       *   "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c".
         */
 -      static const struct interval combining[] = {
 -              { 0x0300, 0x036F }, { 0x0483, 0x0489 }, { 0x0591, 0x05BD },
 -              { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 },
 -              { 0x05C7, 0x05C7 }, { 0x0600, 0x0604 }, { 0x0610, 0x061A },
 -              { 0x064B, 0x065F }, { 0x0670, 0x0670 }, { 0x06D6, 0x06E4 },
 -              { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x070F, 0x070F },
 -              { 0x0711, 0x0711 }, { 0x0730, 0x074A }, { 0x07A6, 0x07B0 },
 -              { 0x0901, 0x0902 }, { 0x093C, 0x093C }, { 0x0941, 0x0948 },
 -              { 0x094D, 0x094D }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 },
 -              { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 },
 -              { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 },
 -              { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 },
 -              { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 },
 -              { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 },
 -              { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 },
 -              { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 },
 -              { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 },
 -              { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
 -              { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
 -              { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 },
 -              { 0x0CCC, 0x0CCD }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
 -              { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
 -              { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
 -              { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
 -              { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
 -              { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
 -              { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
 -              { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
 -              { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
 -              { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x1712, 0x1714 },
 -              { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, { 0x1772, 0x1773 },
 -              { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 },
 -              { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, { 0x180B, 0x180D },
 -              { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 },
 -              { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x200B, 0x200F },
 -              { 0x202A, 0x202E }, { 0x2060, 0x2063 }, { 0x206A, 0x206F },
 -              { 0x20D0, 0x20EA }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
 -              { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE23 },
 -              { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x1D167, 0x1D169 },
 -              { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B },
 -              { 0x1D1AA, 0x1D1AD }, { 0xE0001, 0xE0001 },
 -              { 0xE0020, 0xE007F }, { 0xE0100, 0xE01EF }
 -      };
 +#include "unicode_width.h"
  
        /* test for 8-bit control characters */
        if (ch == 0)
                return -1;
  
        /* binary search in table of non-spacing characters */
 -      if (bisearch(ch, combining, sizeof(combining)
 +      if (bisearch(ch, zero_width, sizeof(zero_width)
                                / sizeof(struct interval) - 1))
                return 0;
  
 -      /*
 -       * If we arrive here, ch is neither a combining nor a C0/C1
 -       * control character.
 -       */
 +      /* binary search in table of double width characters */
 +      if (bisearch(ch, double_width, sizeof(double_width)
 +                              / sizeof(struct interval) - 1))
 +              return 2;
  
 -      return 1 +
 -              (ch >= 0x1100 &&
 -                    /* Hangul Jamo init. consonants */
 -               (ch <= 0x115f ||
 -                ch == 0x2329 || ch == 0x232a ||
 -                  /* CJK ... Yi */
 -                (ch >= 0x2e80 && ch <= 0xa4cf &&
 -                 ch != 0x303f) ||
 -                /* Hangul Syllables */
 -                (ch >= 0xac00 && ch <= 0xd7a3) ||
 -                /* CJK Compatibility Ideographs */
 -                (ch >= 0xf900 && ch <= 0xfaff) ||
 -                /* CJK Compatibility Forms */
 -                (ch >= 0xfe30 && ch <= 0xfe6f) ||
 -                /* Fullwidth Forms */
 -                (ch >= 0xff00 && ch <= 0xff60) ||
 -                (ch >= 0xffe0 && ch <= 0xffe6) ||
 -                (ch >= 0x20000 && ch <= 0x2fffd) ||
 -                (ch >= 0x30000 && ch <= 0x3fffd)));
 +      return 1;
  }
  
  /*
@@@ -567,8 -629,8 +567,8 @@@ int mbs_chrlen(const char **text, size_
  }
  
  /*
-  * Pick the next char from the stream, folding as an HFS+ filename comparison
-  * would. Note that this is _not_ complete by any means. It's just enough
+  * Pick the next char from the stream, ignoring codepoints an HFS+ would.
+  * Note that this is _not_ complete by any means. It's just enough
   * to make is_hfs_dotgit() work, and should not be used otherwise.
   */
  static ucs_char_t next_hfs_char(const char **in)
                        continue;
                }
  
-               /*
-                * there's a great deal of other case-folding that occurs,
-                * but this is enough to catch anything that will convert
-                * to ".git"
-                */
-               return tolower(out);
+               return out;
        }
  }
  
@@@ -618,10 -675,23 +613,23 @@@ int is_hfs_dotgit(const char *path
  {
        ucs_char_t c;
  
-       if (next_hfs_char(&path) != '.' ||
-           next_hfs_char(&path) != 'g' ||
-           next_hfs_char(&path) != 'i' ||
-           next_hfs_char(&path) != 't')
+       c = next_hfs_char(&path);
+       if (c != '.')
+               return 0;
+       c = next_hfs_char(&path);
+       /*
+        * there's a great deal of other case-folding that occurs
+        * in HFS+, but this is enough to catch anything that will
+        * convert to ".git"
+        */
+       if (c != 'g' && c != 'G')
+               return 0;
+       c = next_hfs_char(&path);
+       if (c != 'i' && c != 'I')
+               return 0;
+       c = next_hfs_char(&path);
+       if (c != 't' && c != 'T')
                return 0;
        c = next_hfs_char(&path);
        if (c && !is_dir_sep(c))