Skip to content

Commit 5bb6dc7

Browse files
committed
Merge pull request #10 from kblees/kb/symlinks
Allow native symlinks to non-existing targets in 'nativestrict' mode
2 parents a88c376 + f60ae88 commit 5bb6dc7

File tree

1 file changed

+32
-9
lines changed

1 file changed

+32
-9
lines changed

winsup/cygwin/path.cc

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
16891689
path_conv win32_oldpath;
16901690
PUNICODE_STRING final_oldpath, final_newpath;
16911691
UNICODE_STRING final_oldpath_buf;
1692+
bool isdir;
16921693

16931694
if (isabspath (oldpath))
16941695
{
@@ -1749,14 +1750,37 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
17491750
wcpcpy (e_old, c_old);
17501751
}
17511752
}
1752-
/* If the symlink target doesn't exist, don't create native symlink.
1753-
Otherwise the directory flag in the symlink is potentially wrong
1754-
when the target comes into existence, and native tools will fail.
1755-
This is so screwball. This is no problem on AFS, fortunately. */
1756-
if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ())
1753+
1754+
/* The directory flag in the symlink must match the target type,
1755+
otherwise native tools will fail (fortunately this is no problem
1756+
on AFS). Do our best to guess the symlink type correctly. */
1757+
if (win32_oldpath.exists () || win32_oldpath.fs_is_afs ())
17571758
{
1758-
SetLastError (ERROR_FILE_NOT_FOUND);
1759-
return -1;
1759+
/* If the target exists (or on AFS), check the target type. Note
1760+
that this may still be wrong if the target is changed after
1761+
creating the symlink (e.g. in bulk operations such as rsync,
1762+
unpacking archives or VCS checkouts). */
1763+
isdir = win32_oldpath.isdir ();
1764+
}
1765+
else
1766+
{
1767+
if (allow_winsymlinks == WSYM_nativestrict)
1768+
{
1769+
/* In nativestrict mode, if the target does not exist, use
1770+
trailing '/' in the target path as hint to create a
1771+
directory symlink. */
1772+
ssize_t len = strlen(oldpath);
1773+
isdir = len && isdirsep(oldpath[len - 1]);
1774+
}
1775+
else
1776+
{
1777+
/* In native mode, if the target does not exist, fall back
1778+
to creating a Cygwin symlink file (or in case of MSys:
1779+
try to copy the (non-existing) target, which will of
1780+
course fail). */
1781+
SetLastError (ERROR_FILE_NOT_FOUND);
1782+
return -1;
1783+
}
17601784
}
17611785
/* Don't allow native symlinks to Cygwin special files. However, the
17621786
caller shoud know because this case shouldn't be covered by the
@@ -1787,8 +1811,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
17871811
}
17881812
/* Try to create native symlink. */
17891813
if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer,
1790-
win32_oldpath.isdir ()
1791-
? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
1814+
isdir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
17921815
{
17931816
/* Repair native newpath, we still need it. */
17941817
final_newpath->Buffer[1] = L'?';

0 commit comments

Comments
 (0)