Skip to content

Commit 4b2236a

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 8fd6d81 + 412b3e6 commit 4b2236a

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
@@ -1868,7 +1868,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
18681868
path_conv win32_oldpath;
18691869
PUNICODE_STRING final_oldpath, final_newpath;
18701870
UNICODE_STRING final_oldpath_buf;
1871-
DWORD flags;
1871+
DWORD flags = 0;
18721872

18731873
if (isabspath (oldpath))
18741874
{
@@ -1929,14 +1929,39 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
19291929
wcpcpy (e_old, c_old);
19301930
}
19311931
}
1932-
/* If the symlink target doesn't exist, don't create native symlink.
1933-
Otherwise the directory flag in the symlink is potentially wrong
1934-
when the target comes into existence, and native tools will fail.
1935-
This is so screwball. This is no problem on AFS, fortunately. */
1936-
if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ())
1932+
1933+
/* The directory flag in the symlink must match the target type,
1934+
otherwise native tools will fail (fortunately this is no problem
1935+
on AFS). Do our best to guess the symlink type correctly. */
1936+
if (win32_oldpath.exists () || win32_oldpath.fs_is_afs ())
19371937
{
1938-
SetLastError (ERROR_FILE_NOT_FOUND);
1939-
return -1;
1938+
/* If the target exists (or on AFS), check the target type. Note
1939+
that this may still be wrong if the target is changed after
1940+
creating the symlink (e.g. in bulk operations such as rsync,
1941+
unpacking archives or VCS checkouts). */
1942+
if (win32_oldpath.isdir ())
1943+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
1944+
}
1945+
else
1946+
{
1947+
if (allow_winsymlinks == WSYM_nativestrict)
1948+
{
1949+
/* In nativestrict mode, if the target does not exist, use
1950+
trailing '/' in the target path as hint to create a
1951+
directory symlink. */
1952+
ssize_t len = strlen(oldpath);
1953+
if (len && isdirsep(oldpath[len - 1]))
1954+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
1955+
}
1956+
else
1957+
{
1958+
/* In native mode, if the target does not exist, fall back
1959+
to creating a Cygwin symlink file (or in case of MSys:
1960+
try to copy the (non-existing) target, which will of
1961+
course fail). */
1962+
SetLastError (ERROR_FILE_NOT_FOUND);
1963+
return -1;
1964+
}
19401965
}
19411966
/* Don't allow native symlinks to Cygwin special files. However, the
19421967
caller shoud know because this case shouldn't be covered by the
@@ -1965,7 +1990,6 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
19651990
final_oldpath->Buffer[1] = L'\\';
19661991
}
19671992
/* Try to create native symlink. */
1968-
flags = win32_oldpath.isdir () ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
19691993
if (wincap.has_unprivileged_createsymlink ())
19701994
flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
19711995
if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer,

0 commit comments

Comments
 (0)