Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2023-04-18 14:52:50 +0300
committerCorinna Vinschen <corinna@vinschen.de>2023-04-18 14:53:09 +0300
commit4b8222983f914a7950987802e73fc069dffc3058 (patch)
tree3dd757ff281faeefddd59c9edfc8fab652a2d37e
parentf87469dd5bcae461bd9fe4da4ee4958ecf353749 (diff)
Cygwin: fix errno values set by readlinkat
readlinkat(fd, "", ...) is supposed to return ENOENT per POSIX, but Cygwin returns EBADF. At the same time, we have to maintain the special feature of glibc that readlinkat(fd, "", ...) operates on fd, if fd is pointing at a symlink opened with O_PATH|O_NOFOLLOW. And, while fixing that, readlinkat(fd, path, ...) *still* has to set errno to EBADF, if fd is an invalid descriptor *and* path is a relative path. This required to change the evaluation order in the helper function gen_full_path_at. Last but not least, in case of the aforementioned glibc-like special handling for symlink descriptors, we have to make sure that errors from gen_full_path_at are not spilled into that special handling. Fixes: 6cc05784e16a ("Cygwin: readlinkat: allow pathname to be empty") Reported-by: Bruno Haible <bruno@clisp.org> Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
-rw-r--r--winsup/cygwin/release/3.4.73
-rw-r--r--winsup/cygwin/syscalls.cc42
2 files changed, 25 insertions, 20 deletions
diff --git a/winsup/cygwin/release/3.4.7 b/winsup/cygwin/release/3.4.7
index 8ecfbc30a..7bc7d4a1c 100644
--- a/winsup/cygwin/release/3.4.7
+++ b/winsup/cygwin/release/3.4.7
@@ -18,3 +18,6 @@ Bug Fixes
- Fix return value of ilogbl(NaN).
Addresses: https://cygwin.com/pipermail/cygwin/2023-April/253511.html
+
+- Fix error handling in readlinkat.
+ Addresses: https://cygwin.com/pipermail/cygwin/2023-April/253510.html
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index fff8af009..a4e4af626 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -4415,19 +4415,6 @@ gen_full_path_at (char *path_ret, int dirfd, const char *pathname,
set_errno (EFAULT);
return -1;
}
- if (pathname)
- {
- if (!*pathname)
- {
- set_errno (ENOENT);
- return -1;
- }
- if (strlen (pathname) >= PATH_MAX)
- {
- set_errno (ENAMETOOLONG);
- return -1;
- }
- }
if (pathname && isabspath_strict (pathname))
stpcpy (path_ret, pathname);
else
@@ -4459,6 +4446,16 @@ gen_full_path_at (char *path_ret, int dirfd, const char *pathname,
}
if (pathname)
{
+ if (!*pathname)
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
+ if (strlen (pathname) >= PATH_MAX)
+ {
+ set_errno (ENAMETOOLONG);
+ return -1;
+ }
if (p[-1] != '/')
*p++ = '/';
stpcpy (p, pathname);
@@ -4803,21 +4800,26 @@ readlinkat (int dirfd, const char *__restrict pathname, char *__restrict buf,
__try
{
char *path = tp.c_get ();
+ int save_errno = errno;
int res = gen_full_path_at (path, dirfd, pathname);
if (res)
{
- if (errno != ENOENT)
+ if (errno != ENOENT && errno != ENOTDIR)
__leave;
/* pathname is an empty string. This is OK if dirfd refers
to a symlink that was opened with O_PATH | O_NOFOLLOW.
- In this case, readlinkat operates on the symlink. */
+ In this case, readlinkat operates on the symlink.
+ Don't propagate errors from gen_full_path_at after this point. */
+ errno = save_errno;
cygheap_fdget cfd (dirfd);
- if (cfd < 0)
- __leave;
- if (!(cfd->issymlink ()
+ if (cfd < 0
+ || (!(cfd->issymlink ()
&& cfd->get_flags () & O_PATH
- && cfd->get_flags () & O_NOFOLLOW))
- __leave;
+ && cfd->get_flags () & O_NOFOLLOW)))
+ {
+ set_errno (ENOENT);
+ __leave;
+ }
strcpy (path, cfd->get_name ());
}
return readlink (path, buf, bufsize);