diff options
author | Ken Brown <kbrown@cornell.edu> | 2021-02-25 07:54:10 -0500 |
---|---|---|
committer | Ken Brown <kbrown@cornell.edu> | 2021-02-25 17:44:18 -0500 |
commit | 182ba1f022fb42b22fd2c7d925bf687227b2b3c7 (patch) | |
tree | e814587d0460934e55a46e42b2d4930b75b96005 | |
parent | 425203384a6c3e19af782c86570740464423eb4d (diff) | |
download | newlib-182ba1f022fb42b22fd2c7d925bf687227b2b3c7.zip newlib-182ba1f022fb42b22fd2c7d925bf687227b2b3c7.tar.gz newlib-182ba1f022fb42b22fd2c7d925bf687227b2b3c7.tar.bz2 |
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.
-rw-r--r-- | winsup/cygwin/syscalls.cc | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 460fe68..6ba4f10 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -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) {} |