is_hfs_dotgit: match other .git files

Both verify_path() and fsck match ".git", ".GIT", and other variants specific to HFS+. Let's allow matching other special files like ".gitmodules", which we'll later use to enforce extra restrictions via verify_path() and fsck. Signed-off-by: Jeff King <peff@peff.net>

Jeff King committed May 2, 2018 at 15:23 UTC 0fc333ba20b43a8afee5023e92cb3384ff4e59a6
2 files changed +51 -12
utf8.c
+46 -12
@@ -619,28 +619,33 @@ static ucs_char_t next_hfs_char(const char **in)
619 }
620 }
621
622 -int is_hfs_dotgit(const char *path)
622 +static int is_hfs_dot_generic(const char *path,
623 + const char *needle, size_t needle_len)
624 {
625 ucs_char_t c;
626
627 c = next_hfs_char(&path);
628 if (c != '.')
629 return 0;
629 - c = next_hfs_char(&path);
630
631 /*
632 * there's a great deal of other case-folding that occurs
633 - * in HFS+, but this is enough to catch anything that will
634 - * convert to ".git"
633 + * in HFS+, but this is enough to catch our fairly vanilla
634 + * hard-coded needles.
635 */
636 - if (c != 'g' && c != 'G')
637 - return 0;
638 - c = next_hfs_char(&path);
639 - if (c != 'i' && c != 'I')
640 - return 0;
641 - c = next_hfs_char(&path);
642 - if (c != 't' && c != 'T')
643 - return 0;
636 + for (; needle_len > 0; needle++, needle_len--) {
637 + c = next_hfs_char(&path);
638 +
639 + /*
640 + * We know our needles contain only ASCII, so we clamp here to
641 + * make the results of tolower() sane.
642 + */
643 + if (c > 127)
644 + return 0;
645 + if (tolower(c) != *needle)
646 + return 0;
647 + }
648 +
649 c = next_hfs_char(&path);
650 if (c && !is_dir_sep(c))
651 return 0;
@@ -648,6 +653,35 @@ int is_hfs_dotgit(const char *path)
653 return 1;
654 }
655
656 +/*
657 + * Inline wrapper to make sure the compiler resolves strlen() on literals at
658 + * compile time.
659 + */
660 +static inline int is_hfs_dot_str(const char *path, const char *needle)
661 +{
662 + return is_hfs_dot_generic(path, needle, strlen(needle));
663 +}
664 +
665 +int is_hfs_dotgit(const char *path)
666 +{
667 + return is_hfs_dot_str(path, "git");
668 +}
669 +
670 +int is_hfs_dotgitmodules(const char *path)
671 +{
672 + return is_hfs_dot_str(path, "gitmodules");
673 +}
674 +
675 +int is_hfs_dotgitignore(const char *path)
676 +{
677 + return is_hfs_dot_str(path, "gitignore");
678 +}
679 +
680 +int is_hfs_dotgitattributes(const char *path)
681 +{
682 + return is_hfs_dot_str(path, "gitattributes");
683 +}
684 +
685 const char utf8_bom[] = "\357\273\277";
686
687 int skip_utf8_bom(char **text, size_t len)
utf8.h
+5
@@ -52,8 +52,13 @@ int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
52 * The path should be NUL-terminated, but we will match variants of both ".git\0"
53 * and ".git/..." (but _not_ ".../.git"). This makes it suitable for both fsck
54 * and verify_path().
55 + *
56 + * Likewise, the is_hfs_dotgitfoo() variants look for ".gitfoo".
57 */
58 int is_hfs_dotgit(const char *path);
59 +int is_hfs_dotgitmodules(const char *path);
60 +int is_hfs_dotgitignore(const char *path);
61 +int is_hfs_dotgitattributes(const char *path);
62
63 typedef enum {
64 ALIGN_LEFT,