Skip to content

Commit 5ff8a47

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

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
@@ -1693,6 +1693,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
16931693
path_conv win32_oldpath;
16941694
PUNICODE_STRING final_oldpath, final_newpath;
16951695
UNICODE_STRING final_oldpath_buf;
1696+
bool isdir;
16961697

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

0 commit comments

Comments
 (0)