summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/path.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r--winsup/cygwin/path.cc59
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;
}
}