Prevent adding .git/.gitmodules only in the root of the repository. This allows adding .git files and directories as long as they are not in the root. Signed-off-by: Lukas Straub --- dir.c | 3 ++- read-cache.c | 59 +++++++++++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/dir.c b/dir.c index fe64be30ed..a959885f50 100644 --- a/dir.c +++ b/dir.c @@ -2145,7 +2145,8 @@ static enum path_treatment treat_path(struct dir_struct *dir, if (!cdir->d_name) return treat_path_fast(dir, untracked, cdir, istate, path, baselen, pathspec); - if (is_dot_or_dotdot(cdir->d_name) || !fspathcmp(cdir->d_name, ".git")) + if (is_dot_or_dotdot(cdir->d_name) || + (path->len == 0 && !fspathcmp(cdir->d_name, ".git"))) return path_none; strbuf_setlen(path, baselen); strbuf_addstr(path, cdir->d_name); diff --git a/read-cache.c b/read-cache.c index 8ed1c29b54..7fb25c23d5 100644 --- a/read-cache.c +++ b/read-cache.c @@ -906,12 +906,7 @@ int ce_same_name(const struct cache_entry *a, const struct cache_entry *b) } /* - * We fundamentally don't like some paths: we don't want - * dot or dot-dot anywhere, and for obvious reasons don't - * want to recurse into ".git" either. - * - * Also, we don't want double slashes or slashes at the - * end that can make pathnames ambiguous. + * We don't want dot or dot-dot anywhere */ static int verify_dotfile(const char *rest, unsigned mode) { @@ -922,10 +917,24 @@ static int verify_dotfile(const char *rest, unsigned mode) */ /* "." is not allowed */ - if (*rest == '\0' || is_dir_sep(*rest)) + if (rest[0] == '\0' || is_dir_sep(rest[0])) + return 0; + + /* ".." is not allowed */ + if (rest[0] == '.' && (rest[1] == '\0' || is_dir_sep(rest[1]))) return 0; - switch (*rest) { + return 1; +} + +static int verify_dotgit(const char *rest, unsigned mode) +{ + /* + * The first character was '.', but that + * has already been discarded, we now test + * the rest. + */ + /* * ".git" followed by NUL or slash is bad. Note that we match * case-insensitively here, even if ignore_case is not set. @@ -935,12 +944,11 @@ static int verify_dotfile(const char *rest, unsigned mode) * Once we've seen ".git", we can also find ".gitmodules", etc (also * case-insensitively). */ - case 'g': - case 'G': + if (rest[0] == 'g' || rest[0] == 'G') { if (rest[1] != 'i' && rest[1] != 'I') - break; + return 1; if (rest[2] != 't' && rest[2] != 'T') - break; + return 1; if (rest[3] == '\0' || is_dir_sep(rest[3])) return 0; if (S_ISLNK(mode)) { @@ -949,17 +957,16 @@ static int verify_dotfile(const char *rest, unsigned mode) (*rest == '\0' || is_dir_sep(*rest))) return 0; } - break; - case '.': - if (rest[1] == '\0' || is_dir_sep(rest[1])) - return 0; } + return 1; } int verify_path(const char *path, unsigned mode) { + const char *orig_path = path; char c = 0; + #define is_root(len) ((len) == 0) if (has_dos_drive_prefix(path)) return 0; @@ -973,8 +980,7 @@ int verify_path(const char *path, unsigned mode) return 1; if (is_dir_sep(c)) { inside: - if (protect_hfs) { - + if (protect_hfs && is_root(path - orig_path)) { if (is_hfs_dotgit(path)) return 0; if (S_ISLNK(mode)) { @@ -982,11 +988,7 @@ int verify_path(const char *path, unsigned mode) return 0; } } - if (protect_ntfs) { -#ifdef GIT_WINDOWS_NATIVE - if (c == '\\') - return 0; -#endif + if (protect_ntfs && is_root(path - orig_path)) { if (is_ntfs_dotgit(path)) return 0; if (S_ISLNK(mode)) { @@ -995,11 +997,20 @@ int verify_path(const char *path, unsigned mode) } } +#ifdef GIT_WINDOWS_NATIVE + if (protect_ntfs && c == '\\') + return 0; +#endif + c = *path++; if ((c == '.' && !verify_dotfile(path, mode)) || is_dir_sep(c) || c == '\0') return 0; - } else if (c == '\\' && protect_ntfs) { + if (c == '.' && is_root(path - orig_path -1) && + !verify_dotgit(path, mode)) + return 0; + } else if (c == '\\' && protect_ntfs && + is_root(path - orig_path)) { if (is_ntfs_dotgit(path)) return 0; if (S_ISLNK(mode)) { -- 2.28.0.217.ge805fe7219