4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-01 12:00:35 +08:00

Cygwin: simplify linkat with AT_EMPTY_PATH

linkat(olddirfd, oldpath, oldname, newdirfd, newname, AT_EMPTY_PATH)
is supposed to create a link to the file referenced by olddirfd if
oldname is the empty string.  Currently this is done via the /proc
filesystem by converting the call to

  linkat(AT_FDCWD, "/proc/self/fd/<olddirfd>", newdirfd, newname,
         AT_SYMLINK_FOLLOW),

which ultimately leads to a call to the appropriate fhandler's link
method.  Simplify this by using cygheap_fdget to obtain the fhandler
directly.
This commit is contained in:
Ken Brown 2021-02-25 07:54:10 -05:00
parent 7d2ac48286
commit f4068e5a33

View File

@ -4962,6 +4962,8 @@ linkat (int olddirfd, const char *oldpathname,
int flags)
{
tmp_pathbuf tp;
fhandler_base *fh = NULL;
__try
{
if (flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH))
@ -4970,21 +4972,25 @@ linkat (int olddirfd, const char *oldpathname,
__leave;
}
char *oldpath = tp.c_get ();
/* AT_EMPTY_PATH with an empty oldpathname is equivalent to
linkat(AT_FDCWD, "/proc/self/fd/<olddirfd>", newdirfd,
newname, AT_SYMLINK_FOLLOW);
Convert the request accordingly. */
if ((flags & AT_EMPTY_PATH) && oldpathname && oldpathname[0] == '\0')
{
/* Operate directly on olddirfd, which can be anything
except a directory. */
if (olddirfd == AT_FDCWD)
{
set_errno (EPERM);
__leave;
}
__small_sprintf (oldpath, "/proc/%d/fd/%d", myself->pid, olddirfd);
flags = AT_SYMLINK_FOLLOW;
cygheap_fdget cfd (olddirfd);
if (cfd < 0)
__leave;
if (cfd->pc.isdir ())
{
set_errno (EPERM);
__leave;
}
fh = cfd;
flags = 0; /* In case AT_SYMLINK_FOLLOW was set. */
}
else if (gen_full_path_at (oldpath, olddirfd, oldpathname))
__leave;
@ -5003,6 +5009,8 @@ linkat (int olddirfd, const char *oldpathname,
}
strcpy (oldpath, old_name.get_posix ());
}
if (fh)
return fh->link (newpath);
return link (oldpath, newpath);
}
__except (EFAULT) {}