diff --git a/abspath.c b/abspath.c index 98579853299427..04c4530f6ae249 100644 --- a/abspath.c +++ b/abspath.c @@ -95,6 +95,9 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path, goto error_out; } + if (platform_strbuf_realpath(resolved, path)) + return resolved->buf; + strbuf_addstr(&remaining, path); get_root_part(resolved, &remaining); diff --git a/compat/mingw.c b/compat/mingw.c index f6b38ee83bfe88..8504474294cf81 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1256,6 +1256,37 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) return NULL; } +char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path) +{ + wchar_t wpath[MAX_PATH]; + HANDLE h; + DWORD ret; + int len; + + if (xutftowcs_path(wpath, path) < 0) + return NULL; + + h = CreateFileW(wpath, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h == INVALID_HANDLE_VALUE) + return NULL; + + ret = GetFinalPathNameByHandleW(h, wpath, ARRAY_SIZE(wpath), 0); + CloseHandle(h); + if (!ret || ret >= ARRAY_SIZE(wpath)) + return NULL; + + len = wcslen(wpath) * 3; + strbuf_grow(resolved, len); + len = xwcstoutf(resolved->buf, normalize_ntpath(wpath), len); + if (len < 0) + return NULL; + resolved->len = len; + return resolved->buf; + +} + char *mingw_getcwd(char *pointer, int len) { wchar_t cwd[MAX_PATH], wpointer[MAX_PATH]; diff --git a/compat/mingw.h b/compat/mingw.h index 797a9f9253ba9e..276015cdc58934 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -471,6 +471,8 @@ extern int (*win32_is_mount_point)(struct strbuf *path); #define PATH_SEP ';' char *mingw_query_user_email(void); #define query_user_email mingw_query_user_email +char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path); +#define platform_strbuf_realpath mingw_strbuf_realpath #if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800) #define PRIuMAX "I64u" #define PRId64 "I64d" diff --git a/git-compat-util.h b/git-compat-util.h index 9d0f00e75d3a27..6c3dd4a5dd3390 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -408,6 +408,10 @@ static inline int git_create_symlink(struct index_state *index, const char *targ #define query_user_email() NULL #endif +#ifndef platform_strbuf_realpath +#define platform_strbuf_realpath(resolved, path) NULL +#endif + #ifdef __TANDEM #include #include diff --git a/t/t3700-add.sh b/t/t3700-add.sh index a649805369dbf0..7419b833e4d1ca 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -421,4 +421,15 @@ test_expect_success CASE_INSENSITIVE_FS 'path is case-insensitive' ' git add "$downcased" ' +test_expect_success MINGW 'can add files via NTFS junctions' ' + test_when_finished "cmd //c rmdir junction && rm -rf target" && + test_create_repo target && + cmd //c "mklink /j junction target" && + >target/via-junction && + git -C junction add "$(pwd)/junction/via-junction" && + echo via-junction >expect && + git -C target diff --cached --name-only >actual && + test_cmp expect actual +' + test_done