Skip to content

Commit 21e03ee

Browse files
kbleesdscho
authored andcommitted
Allow native symlinks to non-existing targets in 'nativestrict' mode
Windows native symlinks must match the type of their target (file or directory), otherwise native Windows tools will fail. Creating symlinks in 'nativestrict' mode currently requires the target to exist in order to check its type. However, the target of a symlink can change at any time after the symlink has been created. Thus users of native symlinks must be prepared to deal with type mismatches anyway. Checking the target type at symlink creation time is not a good reason to violate the symlink() API specification. In 'nativestrict' mode, always create native symlinks. Choose the symlink type according to the target if it exists. Otherwise check the target path for a trailing '/' as hint to create a directory symlink. This allows callers to explicitly specify the expected target type, e.g.: $ ln -s test/ link-to-test $ mkdir test Signed-off-by: Karsten Blees <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent fdff7b5 commit 21e03ee

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)