From 7a3a4c7a2a4fc0d7ac4bb1cd8ac2e6d9b6e52701 Mon Sep 17 00:00:00 2001 From: Kevin Worm Date: Thu, 12 May 2022 10:33:33 +0200 Subject: [PATCH] mingw: respect core.longPaths when initializing a new gitdir Use case: Allow git to checkout a repository or submodule in a directory with a long path when core.longpaths = true. Example: > ./git.exe config --global core.longpaths true > ./git.exe clone https://github.com/git/git.git --recurse-submodules \ /c/eval/git_test/loooooooooooooooooooooooooooooooooooooooooooooooooooooooo\ oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\ oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\ oooooooong Context: $ sh --version GNU bash, version 4.4.23(1)-release (x86_64-pc-msys) $ ./git.exe --version --build-options git version 2.36.1.windows.1 cpu: x86_64 built from commit: e2ff68a2d1426758c78d023f863bfa1e03cbc768 sizeof-long: 4 sizeof-size_t: 8 shell-path: /bin/sh feature: fsmonitor--daemon Error: fatal: '$GIT_DIR' too big. Problem analysis: setup_explicit_git_dir in setup.c uses PATH_MAX to check if the git dir is to long. On Windows PATH_MAX is set by limit.h to 260 and setup_explicit_git_dir ignores core.longpaths. Solution: The implementation is based on the solution proposed by Johannes Schindelin, see: https://github.com/git-for-windows/git/issues/3372#issuecomment-904598455 * Refactor the part of trace2_initialize() that reads the config. * Make tr2_sysenv_cb() a public function. * No longer calling it from trace2_initialize(), but from a static callback function in common-main.c. * Calling read_very_early_config() explicitly in main(), with that static callback function that calls into tr2_sysenv_cb(). * Extend the static callback function for Windows, and parse core.longPaths in that function. * Extend startup_info struct in cache.h with 'int max_long_path' so we can use it in setup_explicit_git_dir instead of PATH_MAX. This fixes https://github.com/git-for-windows/git/issues/3372 Signed-off-by: Kevin Worm Signed-off-by: Johannes Schindelin --- common-main.c | 5 ++++- compat/mingw.h | 6 ++++++ git-compat-util.h | 4 ++++ setup.c | 2 +- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/common-main.c b/common-main.c index 269bb96bf7836c..3a64144960056b 100644 --- a/common-main.c +++ b/common-main.c @@ -27,7 +27,10 @@ static void restore_sigpipe_to_default(void) static int read_very_early_config_cb(const char *key, const char *value, void *d) { - return tr2_sysenv_cb(key, value, d); + if (starts_with(key, "core.")) + return platform_core_config(key, value, d); + else + return tr2_sysenv_cb(key, value, d); } int main(int argc, const char **argv) diff --git a/compat/mingw.h b/compat/mingw.h index c15f6c6303b76a..bead61287aa717 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -552,6 +552,12 @@ int is_valid_win32_path(const char *path, int allow_literal_nul); */ int handle_long_path(wchar_t *path, int len, int max_path, int expand); +static inline int mingw_get_max_path_size(void) +{ + return core_long_paths ? MAX_LONG_PATH : MAX_PATH; +} +#define get_max_path_size mingw_get_max_path_size + /** * Converts UTF-8 encoded string to UTF-16LE. * diff --git a/git-compat-util.h b/git-compat-util.h index 586d1a199a0f0d..38a01e050be208 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -372,6 +372,10 @@ char *gitdirname(char *); #define PATH_MAX 4096 #endif +#ifndef get_max_path_size +#define get_max_path_size() PATH_MAX +#endif + typedef uintmax_t timestamp_t; #define PRItime PRIuMAX #define parse_timestamp strtoumax diff --git a/setup.c b/setup.c index 96d0d6e51024b8..94c7c6b954cbe5 100644 --- a/setup.c +++ b/setup.c @@ -875,7 +875,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv, char *gitfile; int offset; - if (PATH_MAX - 40 < strlen(gitdirenv)) + if (get_max_path_size() - 40 < strlen(gitdirenv)) die(_("'$%s' too big"), GIT_DIR_ENVIRONMENT); gitfile = (char*)read_gitfile(gitdirenv);