diff options
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r-- | winsup/cygwin/path.cc | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 7d1d23d72..53cbf4917 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2261,6 +2261,31 @@ symlink_info::check_sysfile (HANDLE h) return res; } +bool +check_reparse_point_target (PUNICODE_STRING subst) +{ + /* Native mount points, or native non-relative symbolic links, + can be treated as posix symlinks only if the SubstituteName + can be converted from a native NT object namespace name to + a win32 name. We only know how to convert names with two + prefixes : + "\??\UNC\..." + "\??\X:..." + Other reparse points will be treated as files or + directories, not as posix symlinks. + */ + if (RtlEqualUnicodePathPrefix (subst, &ro_u_natp, FALSE)) + { + if (subst->Length >= 6*sizeof(WCHAR) && subst->Buffer[5] == L':' && + (subst->Length == 6*sizeof(WCHAR) || subst->Buffer[6] == L'\\')) + return true; + else if (subst->Length >= 8*sizeof(WCHAR) && + wcsncmp (subst->Buffer + 4, L"UNC\\", 4) == 0) + return true; + } + return false; +} + int symlink_info::check_reparse_point (HANDLE h, bool remote) { @@ -2299,14 +2324,24 @@ symlink_info::check_reparse_point (HANDLE h, bool remote) return 0; } if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK) - /* Windows evaluates native symlink literally. If a remote symlink points - to, say, C:\foo, it will be handled as if the target is the local file - C:\foo. That comes in handy since that's how symlinks are treated under - POSIX as well. */ - RtlInitCountedUnicodeString (&subst, - (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer - + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset), - rp->SymbolicLinkReparseBuffer.SubstituteNameLength); + { + /* Windows evaluates native symlink literally. If a remote symlink points + to, say, C:\foo, it will be handled as if the target is the local file + C:\foo. That comes in handy since that's how symlinks are treated under + POSIX as well. */ + RtlInitCountedUnicodeString (&subst, + (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer + + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset), + rp->SymbolicLinkReparseBuffer.SubstituteNameLength); + if (!(rp->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) && + !check_reparse_point_target (&subst)) + { + /* Unsupport native symlink target prefix. Not treated as symlink. + The return value of -1 indicates name needs to be opened without + FILE_OPEN_REPARSE_POINT flag. */ + return -1; + } + } else if (!remote && rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { /* Don't handle junctions on remote filesystems as symlinks. This type @@ -2318,11 +2353,11 @@ symlink_info::check_reparse_point (HANDLE h, bool remote) (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer + rp->MountPointReparseBuffer.SubstituteNameOffset), rp->MountPointReparseBuffer.SubstituteNameLength); - if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE)) + if (!check_reparse_point_target (&subst)) { - /* Volume mount point. Not treated as symlink. The return - value of -1 is a hint for the caller to treat this as a - volume mount point. */ + /* Volume mount point, or unsupported native target prefix. Not + treated as symlink. The return value of -1 indicates name needs + to be opened without FILE_OPEN_REPARSE_POINT flag. */ return -1; } } |