Checksums: Add back QIODevice api
authorChristian Kamm <mail@ckamm.de>
Thu, 15 Aug 2019 12:04:31 +0000 (14:04 +0200)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:55 +0000 (10:58 +0100)
Because the winvfs plugin needs it. But be more careful about the
device's lifetime this time.

src/common/checksums.cpp
src/common/checksums.h

index c0503cb727daf2d986696a0306b0e3651cd24c29..258abe086f813dff055503e998dd7a23a815142a 100644 (file)
@@ -18,6 +18,7 @@
 #include "config.h"
 #include "filesystembase.h"
 #include "common/checksums.h"
+#include "asserts.h"
 
 #include <QLoggingCategory>
 #include <qtconcurrentrun.h>
@@ -225,21 +226,42 @@ QByteArray ComputeChecksum::checksumType() const
 void ComputeChecksum::start(const QString &filePath)
 {
     qCInfo(lcChecksums) << "Computing" << checksumType() << "checksum of" << filePath << "in a thread";
+    startImpl(std::make_unique<QFile>(filePath));
+}
+
+void ComputeChecksum::start(std::unique_ptr<QIODevice> device)
+{
+    ENFORCE(device);
+    qCInfo(lcChecksums) << "Computing" << checksumType() << "checksum of device" << device.get() << "in a thread";
+    ASSERT(!device->parent());
 
+    startImpl(std::move(device));
+}
+
+void ComputeChecksum::startImpl(std::unique_ptr<QIODevice> device)
+{
     connect(&_watcher, &QFutureWatcherBase::finished,
         this, &ComputeChecksum::slotCalculationDone,
         Qt::UniqueConnection);
 
-    // Capturing "file" extends its lifetime to the lifetime of the new thread.
+    // We'd prefer to move the unique_ptr into the lambda, but that's
+    // awkward with the C++ standard we're on
+    auto sharedDevice = QSharedPointer<QIODevice>(device.release());
+
     // Bug: The thread will keep running even if ComputeChecksum is deleted.
     auto type = checksumType();
-    _watcher.setFuture(QtConcurrent::run([filePath, type]() {
-        QFile file(filePath);
-        if (!file.open(QIODevice::ReadOnly)) {
-            qCWarning(lcChecksums) << "Could not open file" << filePath << "for reading to compute a checksum" << file.errorString();
+    _watcher.setFuture(QtConcurrent::run([sharedDevice, type]() {
+        if (!sharedDevice->open(QIODevice::ReadOnly)) {
+            if (auto file = qobject_cast<QFile *>(sharedDevice.data())) {
+                qCWarning(lcChecksums) << "Could not open file" << file->fileName()
+                        << "for reading to compute a checksum" << file->errorString();
+            } else {
+                qCWarning(lcChecksums) << "Could not open device" << sharedDevice.data()
+                        << "for reading to compute a checksum" << sharedDevice->errorString();
+            }
             return QByteArray();
         }
-        return ComputeChecksum::computeNow(&file, type);
+        return ComputeChecksum::computeNow(sharedDevice.data(), type);
     }));
 }
 
@@ -328,6 +350,12 @@ void ValidateChecksumHeader::start(const QString &filePath, const QByteArray &ch
         calculator->start(filePath);
 }
 
+void ValidateChecksumHeader::start(std::unique_ptr<QIODevice> device, const QByteArray &checksumHeader)
+{
+    if (auto calculator = prepareStart(checksumHeader))
+        calculator->start(std::move(device));
+}
+
 void ValidateChecksumHeader::slotChecksumCalculated(const QByteArray &checksumType,
     const QByteArray &checksum)
 {
index fbd92b3223774b7fdca9bc989c6216f2e17586d5..1e5151c7a0d553e176621aa1ee05c3bd2b5882b8 100644 (file)
@@ -100,6 +100,16 @@ public:
      */
     void start(const QString &filePath);
 
+    /**
+     * Computes the checksum for the given device.
+     *
+     * done() is emitted when the calculation finishes.
+     *
+     * The device ownership transfers into the thread that
+     * will compute the checksum. It must not have a parent.
+     */
+    void start(std::unique_ptr<QIODevice> device);
+
     /**
      * Computes the checksum synchronously.
      */
@@ -117,6 +127,8 @@ private slots:
     void slotCalculationDone();
 
 private:
+    void startImpl(std::unique_ptr<QIODevice> device);
+
     QByteArray _checksumType;
 
     // watcher for the checksum calculation thread
@@ -134,7 +146,7 @@ public:
     explicit ValidateChecksumHeader(QObject *parent = nullptr);
 
     /**
-     * Check a device's actual checksum against the provided checksumHeader
+     * Check a file's actual checksum against the provided checksumHeader
      *
      * If no checksum is there, or if a correct checksum is there, the signal validated()
      * will be emitted. In case of any kind of error, the signal validationFailed() will
@@ -142,6 +154,16 @@ public:
      */
     void start(const QString &filePath, const QByteArray &checksumHeader);
 
+    /**
+     * Check a device's actual checksum against the provided checksumHeader
+     *
+     * Like the other start() but works on an device.
+     *
+     * The device ownership transfers into the thread that
+     * will compute the checksum. It must not have a parent.
+     */
+    void start(std::unique_ptr<QIODevice> device, const QByteArray &checksumHeader);
+
 signals:
     void validated(const QByteArray &checksumType, const QByteArray &checksum);
     void validationFailed(const QString &errMsg);