diff --git a/Documentation/config.txt b/Documentation/config.txt index ab26963d61..0677bd8df5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -234,6 +234,11 @@ core.precomposeunicode:: When false, file names are handled fully transparent by Git, which is backward compatible with older versions of Git. +core.protectHFS:: + If set to true, do not allow checkout of paths that would + be considered equivalent to `.git` on an HFS+ filesystem. + Defaults to `true` on Mac OS, and `false` elsewhere. + core.trustctime:: If false, the ctime differences between the index and the working tree are ignored; useful when the inode change time diff --git a/cache.h b/cache.h index ce377e1354..b600a0c3e4 100644 --- a/cache.h +++ b/cache.h @@ -584,6 +584,7 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; extern int precomposed_unicode; +extern int protect_hfs; /* * The character that begins a commented line in user-editable file diff --git a/config.c b/config.c index e1d66a145b..b519cedc01 100644 --- a/config.c +++ b/config.c @@ -881,6 +881,11 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.protecthfs")) { + protect_hfs = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/config.mak.uname b/config.mak.uname index 82d549e48b..23af148837 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -97,6 +97,7 @@ ifeq ($(uname_S),Darwin) HAVE_DEV_TTY = YesPlease COMPAT_OBJS += compat/precompose_utf8.o BASIC_CFLAGS += -DPRECOMPOSE_UNICODE + BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1 endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease diff --git a/environment.c b/environment.c index 0a15349cfe..828b574a29 100644 --- a/environment.c +++ b/environment.c @@ -63,6 +63,11 @@ int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ struct startup_info *startup_info; unsigned long pack_size_limit_cfg; +#ifndef PROTECT_HFS_DEFAULT +#define PROTECT_HFS_DEFAULT 0 +#endif +int protect_hfs = PROTECT_HFS_DEFAULT; + /* * The character that begins a commented line in user-editable file * that is subject to stripspace. diff --git a/read-cache.c b/read-cache.c index 122be494f3..7f48a08c15 100644 --- a/read-cache.c +++ b/read-cache.c @@ -14,6 +14,7 @@ #include "resolve-undo.h" #include "strbuf.h" #include "varint.h" +#include "utf8.h" static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); @@ -786,6 +787,8 @@ int verify_path(const char *path) return 1; if (is_dir_sep(c)) { inside: + if (protect_hfs && is_hfs_dotgit(path)) + return 0; c = *path++; if ((c == '.' && !verify_dotfile(path)) || is_dir_sep(c) || c == '\0') diff --git a/t/t1014-read-tree-confusing.sh b/t/t1014-read-tree-confusing.sh index eff8aedf7a..ec310d5938 100755 --- a/t/t1014-read-tree-confusing.sh +++ b/t/t1014-read-tree-confusing.sh @@ -11,23 +11,39 @@ test_expect_success 'create base tree' ' tree=$(git rev-parse HEAD^{tree}) ' -while read path; do - test_expect_success "reject $path at end of path" ' +test_expect_success 'enable core.protectHFS for rejection tests' ' + git config core.protectHFS true +' + +while read path pretty; do + : ${pretty:=$path} + test_expect_success "reject $pretty at end of path" ' printf "100644 blob %s\t%s" "$blob" "$path" >tree && bogus=$(git mktree tree && bogus=$(git mktree tree && + ok=$(git mktree