diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 861cfd7f8..c1b6afc67 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,8 @@ +2013-12-07 Corinna Vinschen + + * path.cc (symlink_native): Workaround Windows 8.1 bug: Drop long path + prefix from symlink target path. Add comment to explain why. + 2013-12-06 Christopher Faylor * syscalls.cc (dup): Use cygheap_fdnew properly. diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 91d847455..047810f1d 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1553,7 +1553,6 @@ symlink_native (const char *oldpath, path_conv &win32_newpath) { win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); final_oldpath = win32_oldpath.get_nt_native_path (); - final_oldpath->Buffer[1] = L'\\'; } else { @@ -1591,7 +1590,6 @@ symlink_native (const char *oldpath, path_conv &win32_newpath) { /* 3a. No valid common path prefix: Create absolute symlink. */ final_oldpath = win32_oldpath.get_nt_native_path (); - final_oldpath->Buffer[1] = L'\\'; } else { @@ -1619,15 +1617,34 @@ symlink_native (const char *oldpath, path_conv &win32_newpath) SetLastError (ERROR_FILE_NOT_FOUND); return -1; } - /* Convert native path to DOS UNC path. */ + /* Convert native paths to Win32 UNC paths. */ final_newpath = win32_newpath.get_nt_native_path (); final_newpath->Buffer[1] = L'\\'; + /* oldpath may be relative. Make sure to convert only absolute paths + to Win32 paths. */ + if (final_oldpath->Buffer[0] == L'\\') + { + /* Workaround Windows 8.1 bug. On Windows 8.1, the ShellExecuteW + function does not handle the long path prefix correctly for symlink + targets. Thus, we create simple short paths < MAX_PATH without + long path prefix. */ + if (RtlEqualUnicodePathPrefix (final_oldpath, &ro_u_uncp, TRUE) + && final_oldpath->Length < (MAX_PATH + 6) * sizeof (WCHAR)) + { + final_oldpath->Buffer += 6; + final_oldpath->Buffer[0] = L'\\'; + } + else if (final_oldpath->Length < (MAX_PATH + 4) * sizeof (WCHAR)) + final_oldpath->Buffer += 4; + else /* Stick to long path, fix native prefix for Win32 API calls. */ + final_oldpath->Buffer[1] = L'\\'; + } /* Try to create native symlink. */ if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer, win32_oldpath.isdir () ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0)) { - /* Repair native path, we still need it. */ + /* Repair native newpath, we still need it. */ final_newpath->Buffer[1] = L'?'; return -1; } diff --git a/winsup/cygwin/release/1.7.27 b/winsup/cygwin/release/1.7.27 index 5edb9d069..48f095d14 100644 --- a/winsup/cygwin/release/1.7.27 +++ b/winsup/cygwin/release/1.7.27 @@ -1,3 +1,12 @@ +What changed: +------------- + +- Don't create native symlinks with target paths having long path prefixes + "\\?\" if the target path is shorter than MAX_PATH characters. This works + around a Windows 8.1 bug: The ShellExecuteW fails if the lpFile parameter + points to a native NTFS symlink with a target path prefixed with "\\?\". + + Bug Fixes ---------