Compatibility improvements to reparse point handling.
This commit is contained in:
committed by
Corinna Vinschen
parent
ec86124748
commit
7a4e299a18
@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user