Skip to content
Draft
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
2 changes: 1 addition & 1 deletion apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -3779,7 +3779,7 @@ static int check_preimage(struct apply_state *state,
if (*ce && !(*ce)->ce_mode)
BUG("ce_mode == 0 for path '%s'", old_name);

if (trust_executable_bit)
if (trust_executable_bit || !S_ISREG(st->st_mode))
st_mode = ce_mode_from_stat(*ce, st->st_mode);
else if (*ce)
st_mode = (*ce)->ce_mode;
Expand Down
23 changes: 22 additions & 1 deletion compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,7 @@ int mingw_open (const char *filename, int oflags, ...)
int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
wchar_t wfilename[MAX_LONG_PATH];
open_fn_t open_fn;
WIN32_FILE_ATTRIBUTE_DATA fdata;

DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);

Expand Down Expand Up @@ -891,6 +892,19 @@ int mingw_open (const char *filename, int oflags, ...)
else if (xutftowcs_long_path(wfilename, filename) < 0)
return -1;

/*
* When `symlink` exists and is a symbolic link pointing to a
* non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would
* create that file. Not what we want: Linux would say `EEXIST`
* in that instance, which is therefore what Git expects.
*/
if (create &&
GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&
(fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
errno = EEXIST;
return -1;
}

fd = open_fn(wfilename, oflags, mode);

/*
Expand Down Expand Up @@ -1532,8 +1546,15 @@ char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
*/
if (h == INVALID_HANDLE_VALUE &&
GetLastError() == ERROR_FILE_NOT_FOUND) {
WIN32_FILE_ATTRIBUTE_DATA fdata;
wchar_t *p;

if (GetFileAttributesExW(wpath, GetFileExInfoStandard, &fdata) &&
fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
return NULL; /* must follow symlink */

/* cut last component off of `wpath` */
wchar_t *p = wpath + wcslen(wpath);
p = wpath + wcslen(wpath);

while (p != wpath)
if (*(--p) == L'/' || *p == L'\\')
Expand Down
6 changes: 5 additions & 1 deletion t/t0001-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,11 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
git init --separate-git-dir ../realgitdir
) &&
echo "gitdir: $(pwd)/realgitdir" >expected &&
test_cmp expected newdir/.git &&
case "$GIT_TEST_CMP" in
# `git diff --no-index` does not resolve symlinks
*--no-index*) cmp expected newdir/.git;;
*) test_cmp expected newdir/.git;;
esac &&
test_cmp expected newdir/here &&
test_path_is_dir realgitdir/refs
'
Expand Down
3 changes: 2 additions & 1 deletion t/t0301-credential-cache.sh
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to
rmdir \"\$HOME/dir/\" &&
rm \"\$HOME/.git-credential-cache\"
" &&
mkdir -p -m 700 "$HOME/dir/" &&
mkdir -p "$HOME/dir/" &&
chmod 700 "$HOME/dir/" &&
ln -s "$HOME/dir" "$HOME/.git-credential-cache" &&
check approve cache <<-\EOF &&
protocol=https
Expand Down
2 changes: 1 addition & 1 deletion t/t0600-reffiles-backend.sh
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
esac
'

test_expect_success SYMLINKS 'symref transaction supports symlinks' '
test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' '
test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" &&
git update-ref refs/heads/new @ &&
test_config core.prefersymlinkrefs true &&
Expand Down
24 changes: 17 additions & 7 deletions t/t1006-cat-file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-
echo .. >>expect &&
echo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
echo symlink 3 >expect &&
echo ../ >>expect &&
if test_have_prereq MINGW,SYMLINKS
then
test_write_lines "symlink 2" ..
else
test_write_lines "symlink 3" ../
fi >expect &&
echo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual
'

test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '
echo HEAD: | git cat-file --batch-check >expect &&
echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
if test_have_prereq !MINGW
then
# The `up-down` and `up-down-trailing` symlinks are normalized
# in MSYS in `winsymlinks` mode and are therefore in a
# different shape than Git expects them.
echo HEAD: | git cat-file --batch-check >expect &&
echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual
fi &&
echo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp found actual &&
echo symlink 7 >expect &&
Expand Down
4 changes: 2 additions & 2 deletions t/t1305-config-include.sh
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks'
)
'

test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '
test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink' '
ln -s foo bar &&
(
cd bar &&
Expand All @@ -298,7 +298,7 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '
)
'

test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' '
test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink, icase' '
(
cd bar &&
echo "[includeIf \"gitdir/i:BAR/\"]path=bar8" >>.git/config &&
Expand Down
9 changes: 7 additions & 2 deletions t/t6423-merge-rename-directories.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5158,13 +5158,18 @@ test_setup_12m () {
git switch B &&
git rm dir/subdir/file &&
mkdir dir &&
ln -s /dev/null dir/subdir &&
if test_have_prereq MINGW
then
cmd //c 'mklink dir\subdir NUL'
else
ln -s /dev/null dir/subdir
fi &&
git add . &&
git commit -m "B"
)
}

test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '
test_expect_success SYMLINKS '12m: Change parent of renamed-dir to symlink on other side' '
test_setup_12m &&
(
cd 12m &&
Expand Down
8 changes: 4 additions & 4 deletions t/t7800-difftool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -752,11 +752,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
c
EOF
git difftool --symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual &&

git difftool --no-symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual &&

# The left side contains symlink "c" that points to "b"
Expand Down Expand Up @@ -786,11 +786,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '

EOF
git difftool --symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual &&

git difftool --no-symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual
'

Expand Down
9 changes: 7 additions & 2 deletions t/t9700/test.pl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,12 @@ sub adjust_dirsep {
unlink $tmpfile;

# paths
is($r->repo_path, $abs_repo_dir . "/.git", "repo_path");
my $abs_git_dir = $abs_repo_dir . "/.git";
if ($^O eq 'msys' or $^O eq 'cygwin') {
$abs_git_dir = `cygpath -am "$abs_repo_dir/.git"`;
$abs_git_dir =~ s/\r?\n?$//;
}
is($r->repo_path, $abs_git_dir, "repo_path");
is($r->wc_path, $abs_repo_dir . "/", "wc_path");
is($r->wc_subdir, "", "wc_subdir initial");
$r->wc_chdir("directory1");
Expand All @@ -127,7 +132,7 @@ sub adjust_dirsep {
# Object generation in sub directory
chdir("directory2");
my $r2 = Git->repository();
is($r2->repo_path, $abs_repo_dir . "/.git", "repo_path (2)");
is($r2->repo_path, $abs_git_dir, "repo_path (2)");
is($r2->wc_path, $abs_repo_dir . "/", "wc_path (2)");
is($r2->wc_subdir, "directory2/", "wc_subdir initial (2)");

Expand Down
Loading