Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error: "fatal: '$GIT_DIR' too big" when checking out in a long path with core.longpaths = true. #3877

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions common-main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "cache.h"
#include "config.h"
#include "exec-cmd.h"
#include "attr.h"
#include "trace2/tr2_sysenv.h"

/*
* Many parts of Git have subprograms communicate via pipe, expect the
Expand All @@ -23,6 +25,14 @@ static void restore_sigpipe_to_default(void)
signal(SIGPIPE, SIG_DFL);
}

static int read_very_early_config_cb(const char *key, const char *value, void *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)
{
int result;
Expand All @@ -46,7 +56,10 @@ int main(int argc, const char **argv)

attr_start();

read_very_early_config(read_very_early_config_cb, NULL);

trace2_initialize();

trace2_cmd_start(argv);
trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);

Expand Down
33 changes: 18 additions & 15 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ static int current_directory_len = 0;

int mingw_chdir(const char *dirname)
{
int result;
int result = 0;
wchar_t wdirname[MAX_LONG_PATH];
if (xutftowcs_long_path(wdirname, dirname) < 0)
return -1;
Expand All @@ -954,8 +954,11 @@ int mingw_chdir(const char *dirname)
CloseHandle(hnd);
}

result = _wchdir(normalize_ntpath(wdirname));
if(!SetCurrentDirectoryW(wdirname)) {
result = -1;
}
current_directory_len = GetCurrentDirectoryW(0, NULL);

return result;
}

Expand Down Expand Up @@ -1254,15 +1257,11 @@ unsigned int sleep (unsigned int seconds)

char *mingw_mktemp(char *template)
{
wchar_t wtemplate[MAX_PATH];
wchar_t wtemplate[MAX_LONG_PATH];
int offset = 0;

/* we need to return the path, thus no long paths here! */
if (xutftowcsn(wtemplate, template, MAX_PATH, -1) < 0) {
if (errno == ERANGE)
errno = ENAMETOOLONG;
if (xutftowcs_long_path(wtemplate, template) < 0)
return NULL;
}

if (is_dir_sep(template[0]) && !is_dir_sep(template[1]) &&
iswalpha(wtemplate[0]) && wtemplate[1] == L':') {
Expand All @@ -1278,10 +1277,14 @@ char *mingw_mktemp(char *template)

int mkstemp(char *template)
{
char *filename = mktemp(template);
if (filename == NULL)
wchar_t wtemplate[MAX_LONG_PATH];

if (xutftowcs_long_path(wtemplate, template) < 0)
return -1;
return open(filename, O_RDWR | O_CREAT, 0600);
if (!_wmktemp(wtemplate))
return -1;

return _wopen(wtemplate, O_RDWR | O_CREAT, 0600);
}

int gettimeofday(struct timeval *tv, void *tz)
Expand Down Expand Up @@ -1401,7 +1404,7 @@ char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)

char *mingw_getcwd(char *pointer, int len)
{
wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
wchar_t cwd[MAX_LONG_PATH], wpointer[MAX_LONG_PATH];
DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
HANDLE hnd;

Expand Down Expand Up @@ -3488,16 +3491,16 @@ static PSID get_current_user_sid(void)

int is_path_owned_by_current_sid(const char *path)
{
WCHAR wpath[MAX_PATH];
WCHAR wpath[MAX_LONG_PATH];
PSID sid = NULL;
PSECURITY_DESCRIPTOR descriptor = NULL;
DWORD err;

static wchar_t home[MAX_PATH];
static wchar_t home[MAX_LONG_PATH];

int result = 0;

if (xutftowcs_path(wpath, path) < 0)
if (xutftowcs_long_path(wpath, path) < 0)
return 0;

/*
Expand Down
6 changes: 6 additions & 0 deletions compat/mingw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
9 changes: 7 additions & 2 deletions compat/win32/git.manifest
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity type="win32" name="Git" version="0.0.0.1" />
<asmv3:application>
<asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</asmv3:windowsSettings>
</asmv3:application>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
Expand All @@ -18,7 +23,7 @@
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
Expand Down
4 changes: 4 additions & 0 deletions git-compat-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion git.rc
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ BEGIN
END
END

1 RT_MANIFEST "compat/win32/git.manifest"
1 24 "compat/win32/git.manifest"
2 changes: 1 addition & 1 deletion setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions t/t2031-checkout-long-paths.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,11 @@ test_expect_success SHORTABSPATH 'clean up path close to MAX_PATH' '
test ! -d "$subdir1"
'

test_expect_success 'init with long path' '
p=/123456789abcdef/123456789abcdef/123456789abcdef/123456789abc/ef &&
p=y$p$p$p$p &&
test_config_global core.longpaths true &&
git init $p
'

test_done
2 changes: 1 addition & 1 deletion trace2.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ void trace2_initialize_fl(const char *file, int line)
if (trace2_enabled)
return;

tr2_sysenv_load();
tr2_sysenv_check_size();

if (!tr2_tgt_want_builtins())
return;
Expand Down
20 changes: 9 additions & 11 deletions trace2/tr2_sysenv.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
};
/* clang-format on */

static int tr2_sysenv_cb(const char *key, const char *value, void *d)
/*
* Load Trace2 settings from the system config (usually "/etc/gitconfig"
* unless we were built with a runtime-prefix). These are intended to
* define the default values for Trace2 as requested by the administrator.
*
* Then override with the Trace2 settings from the global config.
*/
int tr2_sysenv_cb(const char *key, const char *value, void *d)
{
int k;

Expand All @@ -75,19 +82,10 @@ static int tr2_sysenv_cb(const char *key, const char *value, void *d)
return 0;
}

/*
* Load Trace2 settings from the system config (usually "/etc/gitconfig"
* unless we were built with a runtime-prefix). These are intended to
* define the default values for Trace2 as requested by the administrator.
*
* Then override with the Trace2 settings from the global config.
*/
void tr2_sysenv_load(void)
void tr2_sysenv_check_size(void)
{
if (ARRAY_SIZE(tr2_sysenv_settings) != TR2_SYSENV_MUST_BE_LAST)
BUG("tr2_sysenv_settings size is wrong");

read_very_early_config(tr2_sysenv_cb, NULL);
}

/*
Expand Down
3 changes: 2 additions & 1 deletion trace2/tr2_sysenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ enum tr2_sysenv_variable {
TR2_SYSENV_MUST_BE_LAST
};

void tr2_sysenv_load(void);
int tr2_sysenv_cb(const char *key, const char *value, void *d);
void tr2_sysenv_check_size(void);

const char *tr2_sysenv_get(enum tr2_sysenv_variable);
const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var);
Expand Down