cygwin: unify reparse point checking code into single function

So far we had two functions checking the content of a reparse point,
readdir_check_reparse_point in fhandler_disk_file.cc for the sake of
readdir, and symlink_info::check_reparse_point for the sake of
generic path checking.

* Rename check_reparse_point_target helper to check_reparse_point_string
  and convert to static function.
* Create new check_reparse_point_target helper containing the core
  reparse point checking code
* Just call check_reparse_point_target from readdir_check_reparse_point
  and symlink_info::check_reparse_point and only perform the unique
  task in those functions.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen
2017-07-24 17:33:20 +02:00
parent 42f1be581c
commit 3e80cefb16
3 changed files with 68 additions and 87 deletions

View File

@ -161,62 +161,25 @@ path_conv::isgood_inode (ino_t ino) const
return true;
}
/* Check reparse point to determine if it should be treated as a posix symlink
or as a normal file/directory. Mount points are treated as normal directories
to match behavior of other systems. Unknown reparse tags are used for
things other than links (HSM, compression, dedup), and generally should be
treated as a normal file/directory. Native symlinks and mount points are
treated as posix symlinks, depending on the prefix of the target name.
This logic needs to agree with equivalent logic in path.cc
symlink_info::check_reparse_point() .
*/
/* Check reparse point to determine if it should be treated as a
posix symlink or as a normal file/directory. Logic is explained
in detail in check_reparse_point_target in path.cc. */
static inline bool
readdir_check_reparse_point (POBJECT_ATTRIBUTES attr, bool remote)
{
bool ret = false;
IO_STATUS_BLOCK io;
NTSTATUS status;
HANDLE reph;
UNICODE_STRING subst;
IO_STATUS_BLOCK io;
tmp_pathbuf tp;
UNICODE_STRING symbuf;
bool ret = false;
if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REPARSE_POINT)))
status = NtOpenFile (&reph, READ_CONTROL, attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
if (NT_SUCCESS (status))
{
PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER)
alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (NT_SUCCESS (NtFsControlFile (reph, NULL, NULL, NULL,
&io, FSCTL_GET_REPARSE_POINT, NULL, 0,
(LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)))
{
/* If reparse point is stored on a remote volume, lstat returns
them as normal files or dirs, not as symlink. For a description,
see the comment preceeding remote check in
symlink_info::check_reparse_point. */
if (!remote && rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
{
RtlInitCountedUnicodeString (&subst,
(WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
+ rp->MountPointReparseBuffer.SubstituteNameOffset),
rp->MountPointReparseBuffer.SubstituteNameLength);
if (check_reparse_point_target (&subst))
ret = true;
}
else if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
{
if (rp->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE)
ret = true;
else
{
RtlInitCountedUnicodeString (&subst,
(WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
+ rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
rp->SymbolicLinkReparseBuffer.SubstituteNameLength);
if (check_reparse_point_target (&subst))
ret = true;
}
}
}
PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
ret = (check_reparse_point_target (reph, remote, rp, &symbuf) > 0);
NtClose (reph);
}
return ret;