Commit 9893f56b8a3f2f1c2136a0888ecd3643d4ff9b11

Carlos Martín Nieto 2018-05-16T14:47:04

path: provide a generic function for checking dogit files on NTFS It checks against the 8.3 shortname variants, including the one which includes the checksum as part of its name.

diff --git a/src/path.c b/src/path.c
index 0f8bbcc..e135e3b 100644
--- a/src/path.c
+++ b/src/path.c
@@ -1620,6 +1620,59 @@ GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size
 	return false;
 }
 
+GIT_INLINE(bool) only_spaces_and_dots(const char *path)
+{
+	const char *c = path;
+
+	for (;; c++) {
+		if (*c == '\0')
+			return true;
+		if (*c != ' ' && *c != '.')
+			return false;
+	}
+
+	return true;
+}
+
+GIT_INLINE(bool) verify_dotgit_ntfs_generic(const char *name, const char *dotgit_name, const char *shortname_pfix)
+{
+	size_t len = strlen(name);
+	size_t dotgit_len = strlen(dotgit_name);
+	int i, saw_tilde;
+
+	if (name[0] == '.' && len >= dotgit_len &&
+	    !strncasecmp(name + 1, dotgit_name, dotgit_len)) {
+		return !only_spaces_and_dots(name + dotgit_len + 1);
+	}
+
+	/* Detect the basic NTFS shortname with the first six chars */
+	if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' &&
+	    name[7] >= '1' && name[7] <= '4')
+		return !only_spaces_and_dots(name + 8);
+
+	/* Catch fallback names */
+	for (i = 0, saw_tilde = 0; i < 8; i++) {
+		if (name[i] == '\0') {
+			return true;
+		} else if (saw_tilde) {
+			if (name[i] < '0' || name[i] > '9')
+				return true;
+		} else if (name[i] == '~') {
+			if (name[i+1] < '1' || name[i+1]  > '9')
+				return true;
+			saw_tilde = 1;
+		} else if (i >= 6) {
+			return true;
+		} else if (name[i] < 0) {
+			return true;
+		} else if (git__tolower(name[i]) != shortname_pfix[i]) {
+			return true;
+		}
+	}
+
+	return !only_spaces_and_dots(name + i);
+}
+
 GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags)
 {
 	if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\')