OSDN Git Service

implement QFileSystemEngine::copyFile() for non-Linux platforms
authorIvailo Monev <xakepa10@laimg.moc>
Fri, 10 Jan 2020 21:01:10 +0000 (21:01 +0000)
committerIvailo Monev <xakepa10@laimg.moc>
Fri, 10 Jan 2020 21:04:10 +0000 (21:04 +0000)
Signed-off-by: Ivailo Monev <xakepa10@laimg.moc>
src/core/io/qfile.cpp
src/core/io/qfilesystemengine_unix.cpp

index 40b085c..b364571 100644 (file)
@@ -755,84 +755,12 @@ QFile::copy(const QString &newName)
         qWarning("QFile::copy: Empty or null file name");
         return false;
     }
-    if (QFile(newName).exists()) {
-        // ### Race condition. If a file is moved in after this, it /will/ be
-        // overwritten. On Unix, the proper solution is to use hardlinks:
-        // return ::link(old, new) && ::remove(old); See also rename().
-        d->setError(QFile::CopyError, tr("Destination file exists"));
-        return false;
-    }
+
     unsetError();
     close();
-    if(error() == QFile::NoError) {
-        if(fileEngine()->copy(newName)) {
-            unsetError();
-            return true;
-        } else {
-            bool error = false;
-            if(!open(QFile::ReadOnly)) {
-                error = true;
-                d->setError(QFile::CopyError, tr("Cannot open %1 for input").arg(d->fileName));
-            } else {
-                QString fileTemplate = QLatin1String("%1/qt_temp.XXXXXX");
-#ifdef QT_NO_TEMPORARYFILE
-                QFile out(fileTemplate.arg(QFileInfo(newName).path()));
-                if (!out.open(QIODevice::ReadWrite))
-                    error = true;
-#else
-                QTemporaryFile out(fileTemplate.arg(QFileInfo(newName).path()));
-                if (!out.open()) {
-                    out.setFileTemplate(fileTemplate.arg(QDir::tempPath()));
-                    if (!out.open())
-                        error = true;
-                }
-#endif
-                if (error) {
-                    out.close();
-                    close();
-                    d->setError(QFile::CopyError, tr("Cannot open for output"));
-                } else {
-                    char block[4096];
-                    qint64 totalRead = 0;
-                    while(!atEnd()) {
-                        qint64 in = read(block, sizeof(block));
-                        if (in <= 0)
-                            break;
-                        totalRead += in;
-                        if(in != out.write(block, in)) {
-                            close();
-                            d->setError(QFile::CopyError, tr("Failure to write block"));
-                            error = true;
-                            break;
-                        }
-                    }
-
-                    if (totalRead != size()) {
-                        // Unable to read from the source. The error string is
-                        // already set from read().
-                        error = true;
-                    }
-                    if (!error && !out.rename(newName)) {
-                        error = true;
-                        close();
-                        d->setError(QFile::CopyError, tr("Cannot create %1 for output").arg(newName));
-                    }
-#ifdef QT_NO_TEMPORARYFILE
-                    if (error)
-                        out.remove();
-#else
-                    if (!error)
-                        out.setAutoRemove(false);
-#endif
-                }
-            }
-            if(!error) {
-                QFile::setPermissions(newName, permissions());
-                close();
-                unsetError();
-                return true;
-            }
-        }
+    if(error() == QFile::NoError && fileEngine()->copy(newName)) {
+        unsetError();
+        return true;
     }
     return false;
 }
index 4539566..1a3ba4e 100644 (file)
@@ -36,6 +36,7 @@
 #include "qfsfileengine.h"
 #include "qfile.h"
 #include "qfileinfo.h"
+#include "qcore_unix_p.h"
 
 #include <stdlib.h> // for realpath()
 #include <unistd.h>
@@ -355,15 +356,6 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
 //static
 bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
 {
-#ifdef Q_OS_LINUX
-
-// not in qplatformdefs.h since it is Linux specific
-#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
-#  define QT_SENDFILE ::sendfile64
-#else
-#  define QT_SENDFILE ::sendfile
-#endif
-
     QT_STATBUF st;
     if (QT_STAT(source.nativeFilePath().constData(), &st) == 0) {
         if (!S_ISREG(st.st_mode))
@@ -383,31 +375,56 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst
         return false;
     }
 
-    QT_OFF_T tosend = st.st_size;
-    ssize_t sendresult = QT_SENDFILE(targetfd, sourcefd, Q_NULLPTR, tosend);
-    while (sendresult != tosend) {
+    QT_OFF_T tocopy = st.st_size;
+
+#ifdef Q_OS_LINUX
+// not in qplatformdefs.h since it is platform specific
+#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
+#  define QT_SENDFILE ::sendfile64
+#else
+#  define QT_SENDFILE ::sendfile
+#endif
+
+    ssize_t sendresult = QT_SENDFILE(targetfd, sourcefd, Q_NULLPTR, tocopy);
+    while (sendresult != tocopy) {
         if (sendresult == -1) {
             error = QSystemError(errno, QSystemError::StandardLibraryError);
             ::close(sourcefd);
             ::close(targetfd);
             return false;
         }
-        tosend -= sendresult;
-        sendresult = QT_SENDFILE(targetfd, sourcefd, &tosend, tosend);
+        tocopy -= sendresult;
+        sendresult = QT_SENDFILE(targetfd, sourcefd, &tocopy, tocopy);
     }
+#undef QT_SENDFILE
+// TODO: FreeBSD sendfile() support, signature is different
+#else
+    size_t totalwrite = 0;
+    char copybuffer[BUFSIZ]; // BUFSIZ is defined in stdio.h
+    while (QT_OFF_T(totalwrite) != tocopy) {
+        const size_t readresult = QT_READ(sourcefd, copybuffer, sizeof(copybuffer));
+        if (readresult == -1) {
+            error = QSystemError(errno, QSystemError::StandardLibraryError);
+            ::close(sourcefd);
+            ::close(targetfd);
+            return false;
+        }
+
+        const size_t writeresult = QT_WRITE(targetfd, copybuffer, readresult);
+        if (writeresult != readresult) {
+            error = QSystemError(errno, QSystemError::StandardLibraryError);
+            ::close(sourcefd);
+            ::close(targetfd);
+            return false;
+        }
+
+        totalwrite += readresult;
+    }
+#endif
 
     ::close(sourcefd);
     ::close(targetfd);
     return true;
-
-#undef QT_SENDFILE
-
-#else
-    Q_UNUSED(source);
-    Q_UNUSED(target);
-    error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented
-    return false;
-#endif // Q_OS_LINUX
 }
 
 //static