Skip to content

Commit

Permalink
Merge pull request git-for-windows#10 from kblees/kb/symlinks
Browse files Browse the repository at this point in the history
Allow native symlinks to non-existing targets in 'nativestrict' mode
  • Loading branch information
dscho committed Nov 25, 2015
2 parents 9f41d6a + 91ddc77 commit 5cfe568
Showing 1 changed file with 32 additions and 9 deletions.
41 changes: 32 additions & 9 deletions winsup/cygwin/path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,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 @@ -1779,14 +1780,37 @@ 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;
}
}
/* Don't allow native symlinks to Cygwin special files. However, the
caller shoud know because this case shouldn't be covered by the
Expand Down Expand Up @@ -1817,8 +1841,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

0 comments on commit 5cfe568

Please sign in to comment.