Skip to content

Commit 3f8b09b

Browse files
committed
mingw_strbuf_realpath(): handle case of non existent last path component
git often requests `strbuf_realpath(path + "/.git")`, where "./git" does not yet exist on disk. This causes the following to happen: 1. `mingw_strbuf_realpath()` fails 2. Non-mingw `strbuf_realpath()` does the work 3. Result of `strbuf_realpath()` is slightly different, for example it will not normalize the case of disk/folder names 4. `needs_work_tree_config()` becomes confused by these differences 5. clone adds `core.worktree` setting This in turn causes various problems, for example: 1. Repository folder can no longer be renamed/moved without breaking it 2. Using the repository on WSL (Windows Subsystem for Linux) doesn't work, because it has windows-style path saved This fixes #2569 Signed-off-by: Alexandr Miloslavskiy <[email protected]>
1 parent a98b073 commit 3f8b09b

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

compat/mingw.c

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,35 +1287,63 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
12871287
return NULL;
12881288
}
12891289

1290-
char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
1290+
static int realpath_existing_file(struct strbuf *resolved, const char *path, int path_len)
12911291
{
12921292
wchar_t wpath[MAX_PATH];
12931293
HANDLE h;
12941294
DWORD ret;
12951295
int len;
12961296

1297-
if (xutftowcs_path(wpath, path) < 0)
1298-
return NULL;
1297+
if (xutftowcs_path_ex(wpath, path, MAX_PATH, path_len, MAX_PATH, 0) < 0)
1298+
return -1;
12991299

13001300
h = CreateFileW(wpath, 0,
13011301
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
13021302
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
13031303
if (h == INVALID_HANDLE_VALUE)
1304-
return NULL;
1304+
return -1;
13051305

13061306
ret = GetFinalPathNameByHandleW(h, wpath, ARRAY_SIZE(wpath), 0);
13071307
CloseHandle(h);
13081308
if (!ret || ret >= ARRAY_SIZE(wpath))
1309-
return NULL;
1309+
return -1;
13101310

13111311
len = wcslen(wpath) * 3;
13121312
strbuf_grow(resolved, len);
13131313
len = xwcstoutf(resolved->buf, normalize_ntpath(wpath), len);
13141314
if (len < 0)
1315-
return NULL;
1315+
return -1;
13161316
resolved->len = len;
1317-
return resolved->buf;
1317+
return 0;
1318+
}
13181319

1320+
char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
1321+
{
1322+
char *last_component;
1323+
1324+
if (realpath_existing_file(resolved, path, -1) >= 0)
1325+
return resolved->buf;
1326+
1327+
/*
1328+
* strbuf_realpath() allows last path component to not exist.
1329+
* Resolving full path failed, now it's time to try without last component.
1330+
*
1331+
* Retry on all errors to better match behavior of `strbuf_realpath()`.
1332+
* For example, for no-access last directory, `strbuf_realpath()` ignores
1333+
* that (because it doesn't try to `CreateFile()`) and still succeeds.
1334+
*/
1335+
1336+
last_component = find_last_dir_sep(path);
1337+
if (!last_component)
1338+
return NULL;
1339+
1340+
if (realpath_existing_file(resolved, path, last_component - path) < 0)
1341+
return NULL;
1342+
1343+
/* Force / instead of \ in appended component */
1344+
strbuf_addch(resolved, '/');
1345+
strbuf_addstr(resolved, last_component + 1);
1346+
return resolved->buf;
13191347
}
13201348

13211349
char *mingw_getcwd(char *pointer, int len)

t/t5601-clone.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ test_expect_success 'clone respects GIT_WORK_TREE' '
6868
6969
'
7070

71+
test_expect_success CASE_INSENSITIVE_FS 'core.worktree is not added due to path case' '
72+
73+
mkdir UPPERCASE &&
74+
git clone src "$(pwd)/uppercase" &&
75+
test "unset" = "$(git -C UPPERCASE config --default unset core.worktree)"
76+
'
77+
7178
test_expect_success 'clone from hooks' '
7279
7380
test_create_repo r0 &&

0 commit comments

Comments
 (0)