/* Change the protections of file relative to open directory. Linux version. Copyright (C) 2006-2020 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #include #include #include #include #include #include #include #include int fchmodat (int fd, const char *file, mode_t mode, int flag) { if (flag == 0) return INLINE_SYSCALL (fchmodat, 3, fd, file, mode); else if (flag != AT_SYMLINK_NOFOLLOW) return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL); else { /* The kernel system call does not have a mode argument. However, we can create an O_PATH descriptor and change that via /proc (which does not resolve symbolic links). */ int pathfd = __openat_nocancel (fd, file, O_PATH | O_NOFOLLOW | O_CLOEXEC); if (pathfd < 0) /* This may report errors such as ENFILE and EMFILE. The caller can treat them as temporary if necessary. */ return pathfd; char buf[32]; if (__snprintf (buf, sizeof (buf), "/proc/self/fd/%d", pathfd) < 0) { /* This also may report strange error codes to the caller (although snprintf really should not fail). */ __close_nocancel (pathfd); return -1; } /* This operates directly on the symbolic link if it is one. /proc/self/fd files look like symbolic links, but they are not. (fchmod and fchmodat do not work on O_PATH descriptors, similar to fstat before Linux 3.6.) */ int ret = __chmod (buf, mode); if (ret != 0) { if (errno == ENOENT) /* /proc has not been mounted. Without /proc, there is no way to upgrade the O_PATH descriptor to a full descriptor. It is also not possible to re-open the file without O_PATH because the file name may refer to another file, and opening that without O_PATH may have side effects (such as blocking, device rewinding, or releasing POSIX locks). */ __set_errno (EOPNOTSUPP); } __close_nocancel (pathfd); return ret; } } libc_hidden_def (fchmodat)