summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/configure.json14
-rw-r--r--src/corelib/global/minimum-linux.S5
-rw-r--r--src/corelib/global/qconfig-bootstrapped.h1
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp38
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;