Compatibility improvements to reparse point handling.

This commit is contained in:
Joe_Lowe
2017-06-14 13:01:28 -07:00
committed by Corinna Vinschen
parent ec86124748
commit 7a4e299a18
3 changed files with 87 additions and 36 deletions

View File

@ -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;
}
}