Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow native symlinks to non-existing targets in 'nativestrict' mode #10

Merged
merged 1 commit into from
May 21, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions winsup/cygwin/path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1713,6 +1713,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
path_conv win32_oldpath;
PUNICODE_STRING final_oldpath, final_newpath;
UNICODE_STRING final_oldpath_buf;
bool isdir;

if (isabspath (oldpath))
{
Expand Down Expand Up @@ -1773,15 +1774,39 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
wcpcpy (e_old, c_old);
}
}
/* If the symlink target doesn't exist, don't create native symlink.
Otherwise the directory flag in the symlink is potentially wrong
when the target comes into existence, and native tools will fail.
This is so screwball. This is no problem on AFS, fortunately. */
if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ())

/* The directory flag in the symlink must match the target type,
otherwise native tools will fail (fortunately this is no problem
on AFS). Do our best to guess the symlink type correctly. */
if (win32_oldpath.exists () || win32_oldpath.fs_is_afs ())
{
SetLastError (ERROR_FILE_NOT_FOUND);
return -1;
/* If the target exists (or on AFS), check the target type. Note
that this may still be wrong if the target is changed after
creating the symlink (e.g. in bulk operations such as rsync,
unpacking archives or VCS checkouts). */
isdir = win32_oldpath.isdir ();
}
else
{
if (allow_winsymlinks == WSYM_nativestrict)
{
/* In nativestrict mode, if the target does not exist, use
trailing '/' in the target path as hint to create a
directory symlink. */
ssize_t len = strlen(oldpath);
isdir = len && isdirsep(oldpath[len - 1]);
}
else
{
/* In native mode, if the target does not exist, fall back
to creating a Cygwin symlink file (or in case of MSys:
try to copy the (non-existing) target, which will of
course fail). */
SetLastError (ERROR_FILE_NOT_FOUND);
return -1;
}
}

/* Convert native paths to Win32 UNC paths. */
final_newpath = win32_newpath.get_nt_native_path ();
final_newpath->Buffer[1] = L'\\';
Expand All @@ -1806,8 +1831,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
}
/* Try to create native symlink. */
if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer,
win32_oldpath.isdir ()
? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
isdir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
{
/* Repair native newpath, we still need it. */
final_newpath->Buffer[1] = L'?';
Expand Down