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:
parent
425203384a
commit
182ba1f022
|
@ -4962,6 +4962,8 @@ linkat (int olddirfd, const char *oldpathname,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
tmp_pathbuf tp;
|
tmp_pathbuf tp;
|
||||||
|
fhandler_base *fh = NULL;
|
||||||
|
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
if (flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH))
|
if (flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH))
|
||||||
|
@ -4970,21 +4972,25 @@ linkat (int olddirfd, const char *oldpathname,
|
||||||
__leave;
|
__leave;
|
||||||
}
|
}
|
||||||
char *oldpath = tp.c_get ();
|
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')
|
if ((flags & AT_EMPTY_PATH) && oldpathname && oldpathname[0] == '\0')
|
||||||
{
|
{
|
||||||
|
/* Operate directly on olddirfd, which can be anything
|
||||||
|
except a directory. */
|
||||||
if (olddirfd == AT_FDCWD)
|
if (olddirfd == AT_FDCWD)
|
||||||
{
|
{
|
||||||
set_errno (EPERM);
|
set_errno (EPERM);
|
||||||
__leave;
|
__leave;
|
||||||
}
|
}
|
||||||
__small_sprintf (oldpath, "/proc/%d/fd/%d", myself->pid, olddirfd);
|
cygheap_fdget cfd (olddirfd);
|
||||||
flags = AT_SYMLINK_FOLLOW;
|
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))
|
else if (gen_full_path_at (oldpath, olddirfd, oldpathname))
|
||||||
__leave;
|
__leave;
|
||||||
|
@ -5003,6 +5009,8 @@ linkat (int olddirfd, const char *oldpathname,
|
||||||
}
|
}
|
||||||
strcpy (oldpath, old_name.get_posix ());
|
strcpy (oldpath, old_name.get_posix ());
|
||||||
}
|
}
|
||||||
|
if (fh)
|
||||||
|
return fh->link (newpath);
|
||||||
return link (oldpath, newpath);
|
return link (oldpath, newpath);
|
||||||
}
|
}
|
||||||
__except (EFAULT) {}
|
__except (EFAULT) {}
|
||||||
|
|
Loading…
Reference in New Issue