Cygwin: path_conv: add PC_SYM_NOFOLLOW_DIR flag

Usually a trailing slash requires to follow an existing symlink,
even with PC_SYM_NOFOLLOW.  The reason is that "foo/" is equivalent
to "foo/." so the symlink is in fact not the last path component,
"." is.  This is default for almost all scenarios.

PC_SYM_NOFOLLOW_DIR now allows the caller to request not to
follow the symlink even if a trailing slash is given.  This can
be used in callers to perform certain functions Linux-compatible.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2020-01-28 17:40:40 +01:00
parent 2caaa810a3
commit 26425142ce
2 changed files with 21 additions and 7 deletions

View File

@ -1022,20 +1022,33 @@ path_conv::check (const char *src, unsigned opt,
these operations again on the newly derived path. */
else if (symlen > 0)
{
if (component == 0 && !need_directory
if (component == 0
&& (!(opt & PC_SYM_FOLLOW)
|| (is_known_reparse_point ()
&& (opt & PC_SYM_NOFOLLOW_REP))))
{
/* last component of path is a symlink. */
set_symlink (symlen);
if (opt & PC_SYM_CONTENTS)
/* Usually a trailing slash requires to follow a symlink,
even with PC_SYM_NOFOLLOW. The reason is that "foo/"
is equivalent to "foo/." so the symlink is in fact not
the last path component.
PC_SYM_NOFOLLOW_DIR is used to indicate that the
last path component is the target symlink and the
trailing slash is supposed to be ignored. */
if (!need_directory || (opt & PC_SYM_NOFOLLOW_DIR))
{
strcpy (THIS_path, sym.contents);
/* last component of path is a symlink. */
set_symlink (symlen);
/* make sure not to set errno to ENOTDIR. */
need_directory = 0;
if (opt & PC_SYM_CONTENTS)
{
strcpy (THIS_path, sym.contents);
goto out;
}
add_ext = true;
goto out;
}
add_ext = true;
goto out;
}
/* Following a symlink we can't trust the collected
filesystem information any longer. */

View File

@ -59,6 +59,7 @@ enum pathconv_arg
PC_SYM_NOFOLLOW_PROCFD = _BIT (11), /* allow /proc/PID/fd redirection */
PC_KEEP_HANDLE = _BIT (12), /* keep handle for later stat calls */
PC_NO_ACCESS_CHECK = _BIT (13), /* helper flag for error check */
PC_SYM_NOFOLLOW_DIR = _BIT (14), /* don't follow a trailing slash */
PC_DONT_USE = _BIT (31) /* conversion to signed happens. */
};