read-cache: optionally disallow NTFS .git variants

The point of disallowing ".git" in the index is that we would never want to accidentally overwrite files in the repository directory. But this means we need to respect the filesystem's idea of when two paths are equal. The prior commit added a helper to make such a comparison for NTFS and FAT32; let's use it in verify_path(). We make this check optional for two reasons: 1. It restricts the set of allowable filenames, which is unnecessary for people who are not on NTFS nor FAT32. In practice this probably doesn't matter, though, as the restricted names are rather obscure and almost certainly would never come up in practice. 2. It has a minor performance penalty for every path we insert into the index. This patch ties the check to the core.protectNTFS config option. Though this is expected to be most useful on Windows, we allow it to be set everywhere, as NTFS may be mounted on other platforms. The variable does default to on for Windows, though. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Dec 16, 2014 at 23:46 UTC 2b4c6efc82119ba8f4169717473d95d1a89e4c69
7 files changed +34
Documentation/config.txt
+6
@@ -239,6 +239,12 @@ core.protectHFS::
239 be considered equivalent to `.git` on an HFS+ filesystem.
240 Defaults to `true` on Mac OS, and `false` elsewhere.
241
242 +core.protectNTFS::
243 + If set to true, do not allow checkout of paths that would
244 + cause problems with the NTFS filesystem, e.g. conflict with
245 + 8.3 "short" names.
246 + Defaults to `true` on Windows, and `false` elsewhere.
247 +
248 core.trustctime::
249 If false, the ctime differences between the index and the
250 working tree are ignored; useful when the inode change time
cache.h
+1
@@ -585,6 +585,7 @@ extern int core_preload_index;
585 extern int core_apply_sparse_checkout;
586 extern int precomposed_unicode;
587 extern int protect_hfs;
588 +extern int protect_ntfs;
589
590 /*
591 * The character that begins a commented line in user-editable file
config.c
+5
@@ -886,6 +886,11 @@ static int git_default_core_config(const char *var, const char *value)
886 return 0;
887 }
888
889 + if (!strcmp(var, "core.protectntfs")) {
890 + protect_ntfs = git_config_bool(var, value);
891 + return 0;
892 + }
893 +
894 /* Add other config variables here and to Documentation/config.txt. */
895 return 0;
896 }
config.mak.uname
+2
@@ -362,6 +362,7 @@ ifeq ($(uname_S),Windows)
362 EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
363 PTHREAD_LIBS =
364 lib =
365 + BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
366 ifndef DEBUG
367 BASIC_CFLAGS += -GL -Os -MT
368 BASIC_LDFLAGS += -LTCG
@@ -506,6 +507,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
507 COMPAT_OBJS += compat/mingw.o compat/winansi.o \
508 compat/win32/pthread.o compat/win32/syslog.o \
509 compat/win32/dirent.o
510 + BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
511 BASIC_LDFLAGS += -Wl,--large-address-aware
512 EXTLIBS += -lws2_32
513 GITLIBS += git.res
environment.c
+5
@@ -68,6 +68,11 @@ unsigned long pack_size_limit_cfg;
68 #endif
69 int protect_hfs = PROTECT_HFS_DEFAULT;
70
71 +#ifndef PROTECT_NTFS_DEFAULT
72 +#define PROTECT_NTFS_DEFAULT 0
73 +#endif
74 +int protect_ntfs = PROTECT_NTFS_DEFAULT;
75 +
76 /*
77 * The character that begins a commented line in user-editable file
78 * that is subject to stripspace.
read-cache.c
+2
@@ -789,6 +789,8 @@ int verify_path(const char *path)
789 inside:
790 if (protect_hfs && is_hfs_dotgit(path))
791 return 0;
792 + if (protect_ntfs && is_ntfs_dotgit(path))
793 + return 0;
794 c = *path++;
795 if ((c == '.' && !verify_dotfile(path)) ||
796 is_dir_sep(c) || c == '\0')
t/t1014-read-tree-confusing.sh
+13
@@ -15,8 +15,17 @@ test_expect_success 'enable core.protectHFS for rejection tests' '
15 git config core.protectHFS true
16 '
17
18 +test_expect_success 'enable core.protectNTFS for rejection tests' '
19 + git config core.protectNTFS true
20 +'
21 +
22 while read path pretty; do
23 : ${pretty:=$path}
24 + case "$path" in
25 + *SPACE)
26 + path="${path%SPACE} "
27 + ;;
28 + esac
29 test_expect_success "reject $pretty at end of path" '
30 printf "100644 blob %s\t%s" "$blob" "$path" >tree &&
31 bogus=$(git mktree <tree) &&
@@ -36,6 +45,10 @@ done <<-EOF
45 ${u200c}.Git {u200c}.Git
46 .gI${u200c}T .gI{u200c}T
47 .GiT${u200c} .GiT{u200c}
48 +git~1
49 +.git.SPACE .git.{space}
50 +.\\\\.GIT\\\\foobar backslashes
51 +.git\\\\foobar backslashes2
52 EOF
53
54 test_expect_success 'utf-8 paths allowed with core.protectHFS off' '