Skip to content

Commit e777a80

Browse files
committed
Merge pull request #10 from kblees/kb/symlinks
Allow native symlinks to non-existing targets in 'nativestrict' mode
2 parents b9e1ed8 + 76dff9d commit e777a80

File tree

1 file changed

+33
-9
lines changed

1 file changed

+33
-9
lines changed

winsup/cygwin/path.cc

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,7 +1720,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
17201720
path_conv win32_oldpath;
17211721
PUNICODE_STRING final_oldpath, final_newpath;
17221722
UNICODE_STRING final_oldpath_buf;
1723-
DWORD flags;
1723+
DWORD flags = 0;
17241724

17251725
if (isabspath (oldpath))
17261726
{
@@ -1781,14 +1781,39 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
17811781
wcpcpy (e_old, c_old);
17821782
}
17831783
}
1784-
/* If the symlink target doesn't exist, don't create native symlink.
1785-
Otherwise the directory flag in the symlink is potentially wrong
1786-
when the target comes into existence, and native tools will fail.
1787-
This is so screwball. This is no problem on AFS, fortunately. */
1788-
if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ())
1784+
1785+
/* The directory flag in the symlink must match the target type,
1786+
otherwise native tools will fail (fortunately this is no problem
1787+
on AFS). Do our best to guess the symlink type correctly. */
1788+
if (win32_oldpath.exists () || win32_oldpath.fs_is_afs ())
17891789
{
1790-
SetLastError (ERROR_FILE_NOT_FOUND);
1791-
return -1;
1790+
/* If the target exists (or on AFS), check the target type. Note
1791+
that this may still be wrong if the target is changed after
1792+
creating the symlink (e.g. in bulk operations such as rsync,
1793+
unpacking archives or VCS checkouts). */
1794+
if (win32_oldpath.isdir ())
1795+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
1796+
}
1797+
else
1798+
{
1799+
if (allow_winsymlinks == WSYM_nativestrict)
1800+
{
1801+
/* In nativestrict mode, if the target does not exist, use
1802+
trailing '/' in the target path as hint to create a
1803+
directory symlink. */
1804+
ssize_t len = strlen(oldpath);
1805+
if (len && isdirsep(oldpath[len - 1]))
1806+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
1807+
}
1808+
else
1809+
{
1810+
/* In native mode, if the target does not exist, fall back
1811+
to creating a Cygwin symlink file (or in case of MSys:
1812+
try to copy the (non-existing) target, which will of
1813+
course fail). */
1814+
SetLastError (ERROR_FILE_NOT_FOUND);
1815+
return -1;
1816+
}
17921817
}
17931818
/* Don't allow native symlinks to Cygwin special files. However, the
17941819
caller shoud know because this case shouldn't be covered by the
@@ -1817,7 +1842,6 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
18171842
final_oldpath->Buffer[1] = L'\\';
18181843
}
18191844
/* Try to create native symlink. */
1820-
flags = win32_oldpath.isdir () ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
18211845
if (wincap.has_unprivileged_createsymlink ())
18221846
flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
18231847
if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer,

0 commit comments

Comments
 (0)