Skip to content

Commit 6a16e7a

Browse files
committed
Merge pull request git-for-windows#10 from kblees/kb/symlinks
Allow native symlinks to non-existing targets in 'nativestrict' mode
2 parents 329ada1 + 21e03ee commit 6a16e7a

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
@@ -2012,7 +2012,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
20122012
path_conv win32_oldpath;
20132013
PUNICODE_STRING final_oldpath, final_newpath;
20142014
UNICODE_STRING final_oldpath_buf;
2015-
DWORD flags;
2015+
DWORD flags = 0;
20162016

20172017
if (resolve_symlink_target (oldpath, win32_newpath, win32_oldpath))
20182018
final_oldpath = win32_oldpath.get_nt_native_path ();
@@ -2060,14 +2060,39 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
20602060
wcpcpy (e_old, c_old);
20612061
}
20622062
}
2063-
/* If the symlink target doesn't exist, don't create native symlink.
2064-
Otherwise the directory flag in the symlink is potentially wrong
2065-
when the target comes into existence, and native tools will fail.
2066-
This is so screwball. This is no problem on AFS, fortunately. */
2067-
if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ())
2063+
2064+
/* The directory flag in the symlink must match the target type,
2065+
otherwise native tools will fail (fortunately this is no problem
2066+
on AFS). Do our best to guess the symlink type correctly. */
2067+
if (win32_oldpath.exists () || win32_oldpath.fs_is_afs ())
20682068
{
2069-
SetLastError (ERROR_FILE_NOT_FOUND);
2070-
return -1;
2069+
/* If the target exists (or on AFS), check the target type. Note
2070+
that this may still be wrong if the target is changed after
2071+
creating the symlink (e.g. in bulk operations such as rsync,
2072+
unpacking archives or VCS checkouts). */
2073+
if (win32_oldpath.isdir ())
2074+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
2075+
}
2076+
else
2077+
{
2078+
if (allow_winsymlinks == WSYM_nativestrict)
2079+
{
2080+
/* In nativestrict mode, if the target does not exist, use
2081+
trailing '/' in the target path as hint to create a
2082+
directory symlink. */
2083+
ssize_t len = strlen(oldpath);
2084+
if (len && isdirsep(oldpath[len - 1]))
2085+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
2086+
}
2087+
else
2088+
{
2089+
/* In native mode, if the target does not exist, fall back
2090+
to creating a Cygwin symlink file (or in case of MSys:
2091+
try to copy the (non-existing) target, which will of
2092+
course fail). */
2093+
SetLastError (ERROR_FILE_NOT_FOUND);
2094+
return -1;
2095+
}
20712096
}
20722097
/* Don't allow native symlinks to Cygwin special files. However, the
20732098
caller shoud know because this case shouldn't be covered by the
@@ -2096,7 +2121,6 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
20962121
final_oldpath->Buffer[1] = L'\\';
20972122
}
20982123
/* Try to create native symlink. */
2099-
flags = win32_oldpath.isdir () ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
21002124
if (wincap.has_unprivileged_createsymlink ())
21012125
flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
21022126
if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer,

0 commit comments

Comments
 (0)