diff options
-rw-r--r-- | src/corelib/configure.json | 14 | ||||
-rw-r--r-- | src/corelib/global/minimum-linux.S | 5 | ||||
-rw-r--r-- | src/corelib/global/qconfig-bootstrapped.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_unix.cpp | 38 |
4 files changed, 57 insertions, 1 deletions
diff --git a/src/corelib/configure.json b/src/corelib/configure.json index 44d6ccfdf5..61fc2e16c9 100644 --- a/src/corelib/configure.json +++ b/src/corelib/configure.json @@ -379,6 +379,15 @@ ] } }, + "renameat2": { + "label": "renameat2()", + "type": "compile", + "test": { + "head": "#define _ATFILE_SOURCE 1", + "include": [ "fcntl.h", "stdio.h" ], + "main": "renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_NOREPLACE | RENAME_WHITEOUT);" + } + }, "syslog": { "label": "syslog", "type": "compile", @@ -576,6 +585,11 @@ "condition": "features.statemachine", "output": [ "publicFeature" ] }, + "renameat2": { + "label": "renameat2()", + "condition": "config.linux && tests.renameat2", + "output": [ "privateFeature" ] + }, "slog2": { "label": "slog2", "condition": "libs.slog2", diff --git a/src/corelib/global/minimum-linux.S b/src/corelib/global/minimum-linux.S index 3d97ea7ec8..aa67be44ca 100644 --- a/src/corelib/global/minimum-linux.S +++ b/src/corelib/global/minimum-linux.S @@ -86,6 +86,7 @@ * - eventfd 2.6.23 * - pipe2 & dup3 2.6.27 * - accept4 2.6.28 + * - renameat2 3.16 QT_CONFIG(renameat2) * - getrandom 3.17 QT_CONFIG(getentropy) */ @@ -93,6 +94,10 @@ .long 3 .long 17 .long 0 +#elif QT_CONFIG(renameat2) + .long 3 + .long 16 + .long 0 #else .long 2 .long 6 diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index 398da739e1..f1b99609ce 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -88,6 +88,7 @@ #define QT_NO_QOBJECT #define QT_FEATURE_process -1 #define QT_NO_SYSTEMLOCALE +#define QT_FEATURE_renameat2 -1 #define QT_FEATURE_slog2 -1 #define QT_FEATURE_syslog -1 #define QT_FEATURE_temporaryfile 1 diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index b77cea3f80..79b015938c 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -54,7 +54,6 @@ #include <stdio.h> #include <errno.h> - #if defined(Q_OS_MAC) # include <QtCore/private/qcore_mac_p.h> # include <CoreFoundation/CFBundle.h> @@ -78,6 +77,16 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSString); extern "C" NSString *NSTemporaryDirectory(); #endif +#if defined(Q_OS_LINUX) +# include <sys/syscall.h> +# include <linux/fs.h> + +# if !QT_CONFIG(renameat2) && defined(SYS_renameat2) +static int renameat2(int oldfd, const char *oldpath, int newfd, const char *newpath, unsigned flags) +{ return syscall(SYS_renameat2, oldfd, oldpath, newfd, newpath, flags); } +# endif +#endif + QT_BEGIN_NAMESPACE #if defined(Q_OS_DARWIN) @@ -653,6 +662,33 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy { QFileSystemEntry::NativePath srcPath = source.nativeFilePath(); QFileSystemEntry::NativePath tgtPath = target.nativeFilePath(); + +#if defined(RENAME_NOREPLACE) && (QT_CONFIG(renameat2) || defined(SYS_renameat2)) + if (renameat2(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_NOREPLACE) == 0) + return true; + + // If we're using syscall(), check for ENOSYS; + // if renameat2 came from libc, we don't accept ENOSYS. + if (QT_CONFIG(renameat2) || errno != ENOSYS) { + error = QSystemError(errno, QSystemError::StandardLibraryError); + return false; + } +#endif +#if defined(Q_OS_DARWIN) && defined(RENAME_EXCL) + const auto current = QOperatingSystemVersion::current(); + if (current >= QOperatingSystemVersion::MacOSSierra || + current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 10) || + current >= QOperatingSystemVersion(QOperatingSystemVersion::TvOS, 10) || + current >= QOperatingSystemVersion(QOperatingSystemVersion::WatchOS, 3)) { + if (renameatx_np(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_EXCL) == 0) + return true; + if (errno != ENOTSUP) { + error = QSystemError(errno, QSystemError::StandardLibraryError); + return false; + } + } +#endif + if (::link(srcPath, tgtPath) == 0) { if (::unlink(srcPath) == 0) return true; |