mirror of
https://github.com/git-for-windows/git.git
synced 2026-02-04 03:33:01 -06:00
Merge pull request #2504 from dscho/access-repo-via-junction
Handle `git add <file>` where <file> traverses an NTFS junction
This commit is contained in:
commit
a2bce6d425
@ -93,6 +93,9 @@ static char *strbuf_realpath_1(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);
|
||||
|
||||
|
||||
@ -1238,6 +1238,82 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
|
||||
}
|
||||
#endif
|
||||
|
||||
char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
|
||||
{
|
||||
wchar_t wpath[MAX_PATH];
|
||||
HANDLE h;
|
||||
DWORD ret;
|
||||
int len;
|
||||
const char *last_component = NULL;
|
||||
char *append = NULL;
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* strbuf_realpath() allows the last path component to not exist. If
|
||||
* that is the case, now it's time to try without last component.
|
||||
*/
|
||||
if (h == INVALID_HANDLE_VALUE &&
|
||||
GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
/* cut last component off of `wpath` */
|
||||
wchar_t *p = wpath + wcslen(wpath);
|
||||
|
||||
while (p != wpath)
|
||||
if (*(--p) == L'/' || *p == L'\\')
|
||||
break; /* found start of last component */
|
||||
|
||||
if (p != wpath && (last_component = find_last_dir_sep(path))) {
|
||||
append = xstrdup(last_component + 1); /* skip directory separator */
|
||||
/*
|
||||
* Do not strip the trailing slash at the drive root, otherwise
|
||||
* the path would be e.g. `C:` (which resolves to the
|
||||
* _current_ directory on that drive).
|
||||
*/
|
||||
if (p[-1] == L':')
|
||||
p[1] = L'\0';
|
||||
else
|
||||
*p = L'\0';
|
||||
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) {
|
||||
realpath_failed:
|
||||
FREE_AND_NULL(append);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = GetFinalPathNameByHandleW(h, wpath, ARRAY_SIZE(wpath), 0);
|
||||
CloseHandle(h);
|
||||
if (!ret || ret >= ARRAY_SIZE(wpath))
|
||||
goto realpath_failed;
|
||||
|
||||
len = wcslen(wpath) * 3;
|
||||
strbuf_grow(resolved, len);
|
||||
len = xwcstoutf(resolved->buf, normalize_ntpath(wpath), len);
|
||||
if (len < 0)
|
||||
goto realpath_failed;
|
||||
resolved->len = len;
|
||||
|
||||
if (append) {
|
||||
/* Use forward-slash, like `normalize_ntpath()` */
|
||||
strbuf_complete(resolved, '/');
|
||||
strbuf_addstr(resolved, append);
|
||||
FREE_AND_NULL(append);
|
||||
}
|
||||
|
||||
return resolved->buf;
|
||||
|
||||
}
|
||||
|
||||
char *mingw_getcwd(char *pointer, int len)
|
||||
{
|
||||
wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
|
||||
|
||||
@ -43,6 +43,9 @@ int mingw_is_mount_point(struct strbuf *path);
|
||||
#define PATH_SEP ';'
|
||||
char *mingw_query_user_email(void);
|
||||
#define query_user_email mingw_query_user_email
|
||||
struct strbuf;
|
||||
char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path);
|
||||
#define platform_strbuf_realpath mingw_strbuf_realpath
|
||||
|
||||
/**
|
||||
* Verifies that the specified path is owned by the user running the
|
||||
|
||||
@ -391,6 +391,10 @@ static inline int git_has_dir_sep(const char *path)
|
||||
#define query_user_email() NULL
|
||||
#endif
|
||||
|
||||
#ifndef platform_strbuf_realpath
|
||||
#define platform_strbuf_realpath(resolved, path) NULL
|
||||
#endif
|
||||
|
||||
#ifdef __TANDEM
|
||||
#include <floss.h(floss_execl,floss_execlp,floss_execv,floss_execvp)>
|
||||
#include <floss.h(floss_getpwuid)>
|
||||
|
||||
@ -281,6 +281,14 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'real path works near drive root' '
|
||||
# we need a non-existing path at the drive root; simply skip if C:/xyz exists
|
||||
if test ! -e C:/xyz
|
||||
then
|
||||
test C:/xyz = $(test-tool path-utils real_path C:/xyz)
|
||||
fi
|
||||
'
|
||||
|
||||
test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '
|
||||
ln -s target symlink &&
|
||||
echo "symlink" >expect &&
|
||||
|
||||
@ -548,4 +548,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
|
||||
|
||||
@ -78,6 +78,13 @@ test_expect_success 'clone respects GIT_WORK_TREE' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success CASE_INSENSITIVE_FS 'core.worktree is not added due to path case' '
|
||||
|
||||
mkdir UPPERCASE &&
|
||||
git clone src "$(pwd)/uppercase" &&
|
||||
test "unset" = "$(git -C UPPERCASE config --default unset core.worktree)"
|
||||
'
|
||||
|
||||
test_expect_success 'clone from hooks' '
|
||||
|
||||
test_create_repo r0 &&
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user