From a6749d96927a61dd9ce71d0b7125d09f2bb1f014 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 27 Jul 2017 16:36:03 -0700 Subject: [PATCH] renameat2: port to Solaris 10 * lib/renameat2.c (rename_noreplace): Use lstat, not faccessat with AT_SYMLINK_NOFOLLOW (which is not portable). (renameat): Undef before using, to avoid endless recursion when the replacement renameat calls renameat2 which calls the replacement renameat. (renameat2): Use lstatat, not faccessat with AT_SYMLINK_NOFOLLOW. * modules/renameat2 (Depends-on): Remove faccessat. * modules/renameat-tests (test_renameat_LDADD): * modules/renameat2-tests (test_renameat2_LDADD): Remove $(LIB_EACCESS). --- ChangeLog | 12 ++++++++++++ lib/renameat2.c | 37 +++++++++++++++++++++++-------------- modules/renameat-tests | 2 +- modules/renameat2 | 1 - modules/renameat2-tests | 2 +- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index d922e31a18..ec39037df6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2017-07-27 Paul Eggert + renameat2: port to Solaris 10 + * lib/renameat2.c (rename_noreplace): Use lstat, not faccessat + with AT_SYMLINK_NOFOLLOW (which is not portable). + (renameat): Undef before using, to avoid endless recursion when + the replacement renameat calls renameat2 which calls the + replacement renameat. + (renameat2): Use lstatat, not faccessat with AT_SYMLINK_NOFOLLOW. + * modules/renameat2 (Depends-on): Remove faccessat. + * modules/renameat-tests (test_renameat_LDADD): + * modules/renameat2-tests (test_renameat2_LDADD): + Remove $(LIB_EACCESS). + renameat2: new module Although the Linux syscall renameat2 is not in glibc (yet?), it is useful to have access to its RENAME_NOREPLACE flag. diff --git a/lib/renameat2.c b/lib/renameat2.c index 19df58c1d4..e223653dd8 100644 --- a/lib/renameat2.c +++ b/lib/renameat2.c @@ -51,14 +51,15 @@ errno_fail (int e) static int rename_noreplace (char const *src, char const *dst) { - /* This has a race between the call to faccessat and the call to rename. */ - int r = faccessat (AT_FDCWD, dst, F_OK, AT_EACCESS | AT_SYMLINK_NOFOLLOW); - reurn (r == 0 ? errno_fail (EEXIST) - : errno == ENOENT ? rename (src, dst) - : r); + /* This has a race between the call to lstat and the call to rename. */ + struct stat st; + return (lstat (dst, &st) == 0 ? errno_fail (EEXIST) + : errno == ENOENT ? rename (src, dst) + : -1); } #endif +#undef renameat /* Rename FILE1, in the directory open on descriptor FD1, to FILE2, in the directory open on descriptor FD2. If possible, do it without @@ -91,20 +92,23 @@ renameat2 (int fd1, char const *src, int fd2, char const *dst, int rename_errno = ENOTDIR; struct stat src_st; struct stat dst_st; + bool dst_found_nonexistent = false; if (flags != 0) { - int r; /* RENAME_NOREPLACE is the only flag currently supported. */ if (flags & ~RENAME_NOREPLACE) return errno_fail (ENOTSUP); - /* This has a race between the call to faccessat and the - call to renameat. */ - r = faccessat (fd2, dst, F_OK, AT_EACCESS | AT_SYMLINK_NOFOLLOW); - if (r == 0) - return errno_fail (EEXIST); - if (errno != ENOENT) - return r; + else + { + /* This has a race between the call to lstatat and the calls to + renameat below. */ + if (lstatat (fd2, dst, &dst_st) == 0) + return errno_fail (EEXIST); + if (errno != ENOENT) + return -1; + dst_found_nonexistent = true; + } } /* Let strace see any ENOENT failure. */ @@ -124,7 +128,12 @@ renameat2 (int fd1, char const *src, int fd2, char const *dst, before calling rename. */ if (lstatat (fd1, src, &src_st)) return -1; - if (lstatat (fd2, dst, &dst_st)) + if (dst_found_nonexistent) + { + if (!S_ISDIR (src_st.st_mode)) + return errno_fail (ENOENT); + } + else if (lstatat (fd2, dst, &dst_st)) { if (errno != ENOENT || !S_ISDIR (src_st.st_mode)) return -1; diff --git a/modules/renameat-tests b/modules/renameat-tests index 4e9bf2fa17..970ebd7baa 100644 --- a/modules/renameat-tests +++ b/modules/renameat-tests @@ -17,4 +17,4 @@ configure.ac: Makefile.am: TESTS += test-renameat check_PROGRAMS += test-renameat -test_renameat_LDADD = $(LDADD) $(LIB_EACCESS) @LIBINTL@ +test_renameat_LDADD = $(LDADD) @LIBINTL@ diff --git a/modules/renameat2 b/modules/renameat2 index f0ce1958d0..54f72e1c84 100644 --- a/modules/renameat2 +++ b/modules/renameat2 @@ -10,7 +10,6 @@ m4/renameat.m4 Depends-on: stdio extensions -faccessat fcntl-h filenamecat-lgpl [test $HAVE_RENAMEAT = 0 || test $REPLACE_RENAMEAT = 1] openat-h [test $HAVE_RENAMEAT = 0 || test $REPLACE_RENAMEAT = 1] diff --git a/modules/renameat2-tests b/modules/renameat2-tests index efcc33d33e..accf3c4486 100644 --- a/modules/renameat2-tests +++ b/modules/renameat2-tests @@ -17,4 +17,4 @@ configure.ac: Makefile.am: TESTS += test-renameat2 check_PROGRAMS += test-renameat2 -test_renameat2_LDADD = $(LDADD) $(LIB_EACCESS) @LIBINTL@ +test_renameat2_LDADD = $(LDADD) @LIBINTL@ -- 2.39.5