* path.cc (cnt_bs): New inline function.

(symlink_native): Fix creating relative native symlink.
This commit is contained in:
Corinna Vinschen 2013-06-17 12:37:09 +00:00
parent 42c8e85109
commit 2566c2e600
3 changed files with 63 additions and 4 deletions

View File

@ -1,3 +1,8 @@
2013-06-17 Corinna Vinschen <corinna@vinschen.de>
* path.cc (cnt_bs): New inline function.
(symlink_native): Fix creating relative native symlink.
2013-06-17 Corinna Vinschen <corinna@vinschen.de>
* fhandler_clipboard.cc (fhandler_dev_clipboard::read): Fix buffer

View File

@ -1530,12 +1530,25 @@ symlink_nfs (const char *oldpath, path_conv &win32_newpath)
return 0;
}
/* Count backslashes between s and e. */
static inline int
cnt_bs (PWCHAR s, PWCHAR e)
{
int num = 0;
while (s < e)
if (*s++ == L'\\')
++num;
return num;
}
static int
symlink_native (const char *oldpath, path_conv &win32_newpath)
{
tmp_pathbuf tp;
path_conv win32_oldpath;
PUNICODE_STRING final_oldpath, final_newpath;
UNICODE_STRING final_oldpath_buf;
if (isabspath (oldpath))
{
@ -1554,10 +1567,48 @@ symlink_native (const char *oldpath, path_conv &win32_newpath)
stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
oldpath);
win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
UNICODE_STRING dirpath;
RtlSplitUnicodePath (win32_newpath.get_nt_native_path (), &dirpath, NULL);
final_oldpath = win32_oldpath.get_nt_native_path ();
final_oldpath->Buffer += dirpath.Length / sizeof (WCHAR);
/* Try hard to keep Windows symlink path relative. */
/* 1. Find common path prefix. */
PWCHAR c_old = win32_oldpath.get_nt_native_path ()->Buffer;
PWCHAR c_new = win32_newpath.get_nt_native_path ()->Buffer;
/* Windows compatible == always check case insensitive. */
while (towupper (*c_old++) == towupper (*c_new++))
;
/* The last component could share a common prefix, so make sure we end
up on the first char after the last common backslash. */
while (c_old[-1] != L'\\')
--c_old, --c_new;
/* 2. Check if prefix is long enough. The prefix must at least points to
a complete device: \\?\X:\ or \\?\UNC\server\share\ are the minimum
prefix strings. We start counting behind the \\?\ for speed. */
int num = cnt_bs (win32_oldpath.get_nt_native_path ()->Buffer + 4, c_old);
if (num < 1 /* locale drive. */
|| (win32_oldpath.get_nt_native_path ()->Buffer[6] != L':'
&& num < 3)) /* UNC path. */
{
/* 3a. No valid common path prefix: Create absolute symlink. */
final_oldpath = win32_oldpath.get_nt_native_path ();
final_oldpath->Buffer[1] = L'\\';
}
else
{
/* 3b. Common path prefx. Count number of additional directories
in symlink's path, and prepend as much ".." path components
to the target path. */
PWCHAR e_new = win32_newpath.get_nt_native_path ()->Buffer
+ win32_newpath.get_nt_native_path ()->Length
/ sizeof (WCHAR);
num = cnt_bs (c_new, e_new);
final_oldpath = &final_oldpath_buf;
final_oldpath->Buffer = tp.w_get ();
PWCHAR e_old = final_oldpath->Buffer;
while (num-- > 0)
e_old = wcpcpy (e_old, L"..\\");
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

View File

@ -11,3 +11,6 @@ Bug fixes:
- Fix EFAULT when reading large clipboard.
Fixes: http://cygwin.com/ml/cygwin/2013-06/msg00311.html
- Fix creation of relative native symlinks.
Fixes: http://cygwin.com/ml/cygwin/2013-06/msg00340.html