Skip to content

Commit 510cd1c

Browse files
committed
Merge pull request #10 from kblees/kb/symlinks
Allow native symlinks to non-existing targets in 'nativestrict' mode
2 parents be5ad3c + c91bda7 commit 510cd1c

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
@@ -1713,6 +1713,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
17131713
path_conv win32_oldpath;
17141714
PUNICODE_STRING final_oldpath, final_newpath;
17151715
UNICODE_STRING final_oldpath_buf;
1716+
bool isdir;
17161717

17171718
if (isabspath (oldpath))
17181719
{
@@ -1773,15 +1774,39 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
17731774
wcpcpy (e_old, c_old);
17741775
}
17751776
}
1776-
/* If the symlink target doesn't exist, don't create native symlink.
1777-
Otherwise the directory flag in the symlink is potentially wrong
1778-
when the target comes into existence, and native tools will fail.
1779-
This is so screwball. This is no problem on AFS, fortunately. */
1780-
if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ())
1777+
1778+
/* The directory flag in the symlink must match the target type,
1779+
otherwise native tools will fail (fortunately this is no problem
1780+
on AFS). Do our best to guess the symlink type correctly. */
1781+
if (win32_oldpath.exists () || win32_oldpath.fs_is_afs ())
17811782
{
1782-
SetLastError (ERROR_FILE_NOT_FOUND);
1783-
return -1;
1783+
/* If the target exists (or on AFS), check the target type. Note
1784+
that this may still be wrong if the target is changed after
1785+
creating the symlink (e.g. in bulk operations such as rsync,
1786+
unpacking archives or VCS checkouts). */
1787+
isdir = win32_oldpath.isdir ();
1788+
}
1789+
else
1790+
{
1791+
if (allow_winsymlinks == WSYM_nativestrict)
1792+
{
1793+
/* In nativestrict mode, if the target does not exist, use
1794+
trailing '/' in the target path as hint to create a
1795+
directory symlink. */
1796+
ssize_t len = strlen(oldpath);
1797+
isdir = len && isdirsep(oldpath[len - 1]);
1798+
}
1799+
else
1800+
{
1801+
/* In native mode, if the target does not exist, fall back
1802+
to creating a Cygwin symlink file (or in case of MSys:
1803+
try to copy the (non-existing) target, which will of
1804+
course fail). */
1805+
SetLastError (ERROR_FILE_NOT_FOUND);
1806+
return -1;
1807+
}
17841808
}
1809+
17851810
/* Convert native paths to Win32 UNC paths. */
17861811
final_newpath = win32_newpath.get_nt_native_path ();
17871812
final_newpath->Buffer[1] = L'\\';
@@ -1806,8 +1831,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
18061831
}
18071832
/* Try to create native symlink. */
18081833
if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer,
1809-
win32_oldpath.isdir ()
1810-
? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
1834+
isdir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
18111835
{
18121836
/* Repair native newpath, we still need it. */
18131837
final_newpath->Buffer[1] = L'?';

0 commit comments

Comments
 (0)