git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 3/7] win32: override `fspathcmp()` with a directory separator-aware version

From
Johannes Schindelin via GitGitGadget <gitgitgadget@gmail.com>
Date
Jul 13, 2024, 21:08 UTC
Message-ID
<f46315ac0b24879283846682878139641203d4ae.1720904905.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1760.v3.git.1720904905.gitgitgadget@gmail.com>
From: Johannes Schindelin <johannes.schindelin@gmx.de>

On Windows, the backslash is the directory separator, even if the forward slash can be used, too, at least since Windows NT.

This means that the paths `a/b` and `a\b` are equivalent, and `fspathcmp()` needs to be made aware of that fact.

Note that we have to override both `fspathcmp()` and `fspathncmp()`, and the former cannot be a mere pre-processor constant that transforms calls to `fspathcmp(a, b)` into `fspathncmp(a, b, (size_t)-1)` because the function `report_collided_checkout()` in `unpack-trees.c` wants to assign `list.cmp = fspathcmp`.

Also note that `fspatheq()` does _not_ need to be overridden because it calls `fspathcmp()` internally.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/win32/path-utils.c | 37 +++++++++++++++++++++++++++++++++++++
 compat/win32/path-utils.h |  4 ++++
 dir.c                     |  4 ++--
 dir.h                     |  4 ++--
 git-compat-util.h         |  8 ++++++++
 5 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c
index ebf2f12eb66..b658ca3f811 100644
--- a/compat/win32/path-utils.c
+++ b/compat/win32/path-utils.c
@@ -1,4 +1,5 @@
 #include "../../git-compat-util.h"
+#include "../../environment.h"
 
 int win32_has_dos_drive_prefix(const char *path)
 {
@@ -50,3 +51,39 @@ int win32_offset_1st_component(const char *path)
 
 	return pos + is_dir_sep(*pos) - path;
 }
+
+int win32_fspathncmp(const char *a, const char *b, size_t count)
+{
+	int diff;
+
+	for (;;) {
+		if (!count--)
+			return 0;
+		if (!*a)
+			return *b ? -1 : 0;
+		if (!*b)
+			return +1;
+
+		if (is_dir_sep(*a)) {
+			if (!is_dir_sep(*b))
+				return -1;
+			a++;
+			b++;
+			continue;
+		} else if (is_dir_sep(*b))
+			return +1;
+
+		diff = ignore_case ?
+			(unsigned char)tolower(*a) - (int)(unsigned char)tolower(*b) :
+			(unsigned char)*a - (int)(unsigned char)*b;
+		if (diff)
+			return diff;
+		a++;
+		b++;
+	}
+}
+
+int win32_fspathcmp(const char *a, const char *b)
+{
+	return win32_fspathncmp(a, b, (size_t)-1);
+}
diff --git a/compat/win32/path-utils.h b/compat/win32/path-utils.h
index 65fa3b9263a..a561c700e75 100644
--- a/compat/win32/path-utils.h
+++ b/compat/win32/path-utils.h
@@ -29,5 +29,9 @@ static inline int win32_has_dir_sep(const char *path)
 #define has_dir_sep(path) win32_has_dir_sep(path)
 int win32_offset_1st_component(const char *path);
 #define offset_1st_component win32_offset_1st_component
+int win32_fspathcmp(const char *a, const char *b);
+#define fspathcmp win32_fspathcmp
+int win32_fspathncmp(const char *a, const char *b, size_t count);
+#define fspathncmp win32_fspathncmp
 
 #endif
diff --git a/dir.c b/dir.c
index b7a6625ebda..5a23376bdae 100644
--- a/dir.c
+++ b/dir.c
@@ -95,7 +95,7 @@ int count_slashes(const char *s)
 	return cnt;
 }
 
-int fspathcmp(const char *a, const char *b)
+int git_fspathcmp(const char *a, const char *b)
 {
 	return ignore_case ? strcasecmp(a, b) : strcmp(a, b);
 }
@@ -105,7 +105,7 @@ int fspatheq(const char *a, const char *b)
 	return !fspathcmp(a, b);
 }
 
-int fspathncmp(const char *a, const char *b, size_t count)
+int git_fspathncmp(const char *a, const char *b, size_t count)
 {
 	return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);
 }
diff --git a/dir.h b/dir.h
index 69a76d8bdd3..a3a2f00f5d9 100644
--- a/dir.h
+++ b/dir.h
@@ -541,9 +541,9 @@ int remove_dir_recursively(struct strbuf *path, int flag);
  */
 int remove_path(const char *path);
 
-int fspathcmp(const char *a, const char *b);
+int git_fspathcmp(const char *a, const char *b);
 int fspatheq(const char *a, const char *b);
-int fspathncmp(const char *a, const char *b, size_t count);
+int git_fspathncmp(const char *a, const char *b, size_t count);
 unsigned int fspathhash(const char *str);
 
 /*
diff --git a/git-compat-util.h b/git-compat-util.h
index ca7678a379d..71b4d23f038 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -506,6 +506,14 @@ static inline int git_offset_1st_component(const char *path)
 #define offset_1st_component git_offset_1st_component
 #endif
 
+#ifndef fspathcmp
+#define fspathcmp git_fspathcmp
+#endif
+
+#ifndef fspathncmp
+#define fspathncmp git_fspathncmp
+#endif
+
 #ifndef is_valid_path
 #define is_valid_path(path) 1
 #endif
-- 
gitgitgadget
Previous: Johannes Schindelin via GitGitGadgetNext: Johannes Schindelin via GitGitGadget
Message 28 of 35 in “var(win32): do report the GIT_SHELL_PATH that is actually used”
  1. var(win32): do report the GIT_SHELL_PATH that is actually usedJohannes Schindelin via GitGitGadget, Jul 8, 2024
  2. Junio C HamanoJul 8, 2024
  3. brian m. carlsonJul 8, 2024
  4. Junio C HamanoJul 8, 2024
  5. brian m. carlsonJul 9, 2024
  6. Junio C HamanoJul 9, 2024
  7. Phillip WoodJul 9, 2024
  8. Junio C HamanoJul 8, 2024
  9. Phillip WoodJul 9, 2024
  10. Johannes SchindelinJul 11, 2024
  11. phillip.wood123@gmail.comJul 17, 2024
  12. 0/7 var(win32): do report the GIT_SHELL_PATH that is actually usedJohannes Schindelin via GitGitGadget, Jul 11, 2024
  13. 1/7 run-command: refactor getting the Unix shell path into its own functionJohannes Schindelin via GitGitGadget, Jul 11, 2024
  14. 2/7 strvec: declare the `strvec_push_nodup()` function globallyJohannes Schindelin via GitGitGadget, Jul 11, 2024
  15. 3/7 win32: override `fspathcmp()` with a directory separator-aware versionJohannes Schindelin via GitGitGadget, Jul 11, 2024
  16. Phillip WoodJul 12, 2024
  17. 4/7 mingw(is_msys2_sh): handle forward slashes in the `sh.exe` path, tooJohannes Schindelin via GitGitGadget, Jul 11, 2024
  18. Phillip WoodJul 12, 2024
  19. 5/7 run-command(win32): resolve the path to the Unix shell earlyJohannes Schindelin via GitGitGadget, Jul 11, 2024
  20. 6/7 run-command: declare the `git_shell_path()` function globallyJohannes Schindelin via GitGitGadget, Jul 11, 2024
  21. 7/7 var(win32): do report the GIT_SHELL_PATH that is actually usedJohannes Schindelin via GitGitGadget, Jul 11, 2024
  22. Junio C HamanoJul 12, 2024
  23. Phillip WoodJul 12, 2024
  24. Junio C HamanoJul 12, 2024
  25. 0/7 var(win32): do report the GIT_SHELL_PATH that is actually usedJohannes Schindelin via GitGitGadget, Jul 13, 2024
  26. 1/7 run-command: refactor getting the Unix shell path into its own functionJohannes Schindelin via GitGitGadget, Jul 13, 2024
  27. 2/7 strvec: declare the `strvec_push_nodup()` function globallyJohannes Schindelin via GitGitGadget, Jul 13, 2024
  28. 3/7 win32: override `fspathcmp()` with a directory separator-aware versionJohannes Schindelin via GitGitGadget, Jul 13, 2024
  29. 4/7 mingw(is_msys2_sh): handle forward slashes in the `sh.exe` path, tooJohannes Schindelin via GitGitGadget, Jul 13, 2024
  30. 5/7 run-command(win32): resolve the path to the Unix shell earlyJohannes Schindelin via GitGitGadget, Jul 13, 2024
  31. 6/7 run-command: declare the `git_shell_path()` function globallyJohannes Schindelin via GitGitGadget, Jul 13, 2024
  32. 7/7 var(win32): do report the GIT_SHELL_PATH that is actually usedJohannes Schindelin via GitGitGadget, Jul 13, 2024
  33. Phillip WoodJul 17, 2024
  34. brian m. carlsonJul 17, 2024
  35. Junio C HamanoJul 17, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.