Checksums: Add back QIODevice api

Because the winvfs plugin needs it. But be more careful about the
device's lifetime this time.
This commit is contained in:
Christian Kamm 2019-08-15 14:04:31 +02:00 committed by Kevin Ottens
parent 18e1098e38
commit bade7aedc6
No known key found for this signature in database
GPG key ID: 074BBBCB8DECC9E2
2 changed files with 57 additions and 7 deletions

View 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)
{

View 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);