+2025-08-14 Bruno Haible <bruno@clisp.org>
+
+ lchmod: Use issymlink, issymlinkat.
+ * lib/lchmod.c (lchmod): Use issymlink instead of readlink and
+ issymlinkat instead of readlinkat.
+ * modules/lchmod (Depends-on): Remove readlink. Add issymlink,
+ issymlinkat.
+
2025-08-14 Bruno Haible <bruno@clisp.org>
chown: Avoid a redundant stat() call.
int
lchmod (char const *file, mode_t mode)
{
- char readlink_buf[1];
-
#ifdef O_PATH
/* Open a file descriptor with O_NOFOLLOW, to make sure we don't
follow symbolic links, if /proc is mounted. O_PATH is used to
return fd;
int err;
- if (0 <= readlinkat (fd, "", readlink_buf, sizeof readlink_buf))
- err = EOPNOTSUPP;
- else if (errno == EINVAL)
- {
- static char const fmt[] = "/proc/self/fd/%d";
- char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
- sprintf (buf, fmt, fd);
- err = chmod (buf, mode) == 0 ? 0 : errno == ENOENT ? -1 : errno;
- }
- else
- err = errno == ENOENT ? -1 : errno;
+ {
+ int ret = issymlinkat (fd, "");
+ if (ret > 0)
+ err = EOPNOTSUPP;
+ else if (ret == 0)
+ {
+ static char const fmt[] = "/proc/self/fd/%d";
+ char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
+ sprintf (buf, fmt, fd);
+ err = chmod (buf, mode) == 0 ? 0 : errno == ENOENT ? -1 : errno;
+ }
+ else
+ err = errno == ENOENT ? -1 : errno;
+ }
close (fd);
/* O_PATH + /proc is not supported. */
- if (0 <= readlink (file, readlink_buf, sizeof readlink_buf))
+ if (issymlink (file) > 0)
{
errno = EOPNOTSUPP;
return -1;
m4/lchmod.m4
Depends-on:
+sys_stat-h
+extensions
c99 [test $HAVE_LCHMOD = 0]
errno-h [test $HAVE_LCHMOD = 0]
-extensions
fcntl-h [test $HAVE_LCHMOD = 0]
intprops [test $HAVE_LCHMOD = 0]
+issymlink [test $HAVE_LCHMOD = 0]
+issymlinkat [test $HAVE_LCHMOD = 0]
lstat [test $HAVE_LCHMOD = 0]
-readlink [test $HAVE_LCHMOD = 0]
-sys_stat-h
unistd-h [test $HAVE_LCHMOD = 0]
configure.ac: