-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Linux implementation for renameat function.
+ Copyright (C) 2016-2019 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
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, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
-#include <errno.h>
-#include <fcntl.h>
#include <stdio.h>
+#include <fcntl.h>
#include <sysdep.h>
+#include <errno.h>
-
-/* Rename the file OLD relative to OLDFD to NEW relative to NEWFD. */
int
-renameat (oldfd, old, newfd, new)
- int oldfd;
- const char *old;
- int newfd;
- const char *new;
+__renameat (int oldfd, const char *old, int newfd, const char *new)
{
- static const char procfd[] = "/proc/self/fd/%d/%s";
- char *bufold = NULL;
-
- if (oldfd != AT_FDCWD && old[0] != '/')
- {
- size_t filelen = strlen (old);
- /* Buffer for the path name we are going to use. It consists of
- - the string /proc/self/fd/
- - the file descriptor number
- - the file name provided.
- The final NUL is included in the sizeof. A bit of overhead
- due to the format elements compensates for possible negative
- numbers. */
- size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
- bufold = alloca (buflen);
-
- __snprintf (bufold, buflen, procfd, oldfd, old);
- old = bufold;
- }
-
- char *bufnew = NULL;
-
- if (newfd != AT_FDCWD && new[0] != '/')
- {
- size_t filelen = strlen (new);
- /* Buffer for the path name we are going to use. It consists of
- - the string /proc/self/fd/
- - the file descriptor number
- - the file name provided.
- The final NUL is included in the sizeof. A bit of overhead
- due to the format elements compensates for possible negative
- numbers. */
- size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
- bufnew = alloca (buflen);
-
- __snprintf (bufnew, buflen, procfd, newfd, new);
- new = bufnew;
- }
-
- INTERNAL_SYSCALL_DECL (err);
-
- int result = INTERNAL_SYSCALL (rename, err, 2, old, new);
-
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
- {
- int errval = INTERNAL_SYSCALL_ERRNO (result, err);
- if (errval == ENOTDIR && (bufnew != NULL || bufold != NULL))
- {
- /* This can mean either the file descriptor is invalid or
- /proc is not mounted. */
- struct stat64 st;
-
- if (bufnew != NULL)
- {
- if (__fxstat64 (_STAT_VER, newfd, &st) != 0)
- /* errno is already set correctly. */
- return -1;
-
- /* If /proc is not mounted there is nothing we can do. */
- if (S_ISDIR (st.st_mode)
- && (__xstat64 (_STAT_VER, "/proc/self/fd", &st) != 0
- || !S_ISDIR (st.st_mode)))
- {
- errval = ENOSYS;
- goto out;
- }
- }
-
- if (bufold != NULL)
- {
- if (__fxstat64 (_STAT_VER, oldfd, &st) != 0)
- /* errno is already set correctly. */
- return -1;
-
- /* If /proc is not mounted there is nothing we can do. */
- if (S_ISDIR (st.st_mode)
- && (__xstat64 (_STAT_VER, "/proc/self/fd", &st) != 0
- || !S_ISDIR (st.st_mode)))
- errval = ENOSYS;
- }
- }
-
- out:
- __set_errno (errval);
- result = -1;
- }
-
- return result;
+#ifdef __NR_renameat
+ return INLINE_SYSCALL_CALL (renameat, oldfd, old, newfd, new);
+#else
+ return INLINE_SYSCALL_CALL (renameat2, oldfd, old, newfd, new, 0);
+#endif
}
+libc_hidden_def (__renameat)
+weak_alias (__renameat, renameat)