2015-05-15 16:34:17 +03:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "filesystem.h"
|
|
|
|
#include "transmissionchecksumvalidator.h"
|
|
|
|
#include "syncfileitem.h"
|
|
|
|
#include "propagatorjobs.h"
|
2015-10-01 16:00:33 +03:00
|
|
|
#include "account.h"
|
2015-05-15 16:34:17 +03:00
|
|
|
|
2015-05-22 15:43:47 +03:00
|
|
|
#include <qtconcurrentrun.h>
|
2015-05-15 16:34:17 +03:00
|
|
|
|
|
|
|
namespace OCC {
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
QByteArray makeChecksumHeader(const QByteArray& checksumType, const QByteArray& checksum)
|
|
|
|
{
|
|
|
|
QByteArray header = checksumType;
|
|
|
|
header.append(':');
|
|
|
|
header.append(checksum);
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parseChecksumHeader(const QByteArray& header, QByteArray* type, QByteArray* checksum)
|
|
|
|
{
|
|
|
|
if (header.isEmpty()) {
|
|
|
|
type->clear();
|
|
|
|
checksum->clear();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto idx = header.indexOf(':');
|
|
|
|
if (idx < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*type = header.left(idx);
|
|
|
|
*checksum = header.mid(idx + 1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-10-15 10:39:49 +03:00
|
|
|
bool uploadChecksumEnabled()
|
|
|
|
{
|
|
|
|
static bool enabled = qgetenv("OWNCLOUD_DISABLE_CHECKSUM_UPLOAD").isEmpty();
|
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool downloadChecksumEnabled()
|
|
|
|
{
|
|
|
|
static bool enabled = qgetenv("OWNCLOUD_DISABLE_CHECKSUM_DOWNLOAD").isEmpty();
|
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
ComputeChecksum::ComputeChecksum(QObject* parent)
|
|
|
|
: QObject(parent)
|
2015-05-15 16:34:17 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
void ComputeChecksum::setChecksumType(const QByteArray& type)
|
2015-05-15 16:34:17 +03:00
|
|
|
{
|
|
|
|
_checksumType = type;
|
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
QByteArray ComputeChecksum::checksumType() const
|
2015-05-15 16:34:17 +03:00
|
|
|
{
|
2015-10-01 16:00:33 +03:00
|
|
|
return _checksumType;
|
2015-05-21 15:30:21 +03:00
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
void ComputeChecksum::start(const QString& filePath)
|
2015-05-21 15:30:21 +03:00
|
|
|
{
|
|
|
|
const QString csType = checksumType();
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
// Calculate the checksum in a different thread first.
|
|
|
|
connect( &_watcher, SIGNAL(finished()),
|
|
|
|
this, SLOT(slotCalculationDone()),
|
|
|
|
Qt::UniqueConnection );
|
|
|
|
if( csType == checkSumMD5C ) {
|
|
|
|
_watcher.setFuture(QtConcurrent::run(FileSystem::calcMd5, filePath));
|
|
|
|
|
|
|
|
} else if( csType == checkSumSHA1C ) {
|
|
|
|
_watcher.setFuture(QtConcurrent::run( FileSystem::calcSha1, filePath));
|
|
|
|
}
|
2015-05-15 16:34:17 +03:00
|
|
|
#ifdef ZLIB_FOUND
|
2015-10-14 16:03:40 +03:00
|
|
|
else if( csType == checkSumAdlerC) {
|
|
|
|
_watcher.setFuture(QtConcurrent::run(FileSystem::calcAdler32, filePath));
|
|
|
|
}
|
2015-05-15 16:34:17 +03:00
|
|
|
#endif
|
2015-10-14 16:03:40 +03:00
|
|
|
else {
|
|
|
|
// for an unknown checksum or no checksum, we're done right now
|
|
|
|
if( !csType.isEmpty() ) {
|
|
|
|
qDebug() << "Unknown checksum type:" << csType;
|
2015-05-15 16:34:17 +03:00
|
|
|
}
|
2015-10-14 16:03:40 +03:00
|
|
|
emit done(QByteArray(), QByteArray());
|
2015-05-15 16:34:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
void ComputeChecksum::slotCalculationDone()
|
2015-05-15 16:34:17 +03:00
|
|
|
{
|
|
|
|
QByteArray checksum = _watcher.future().result();
|
2015-10-14 16:03:40 +03:00
|
|
|
emit done(_checksumType, checksum);
|
|
|
|
}
|
2015-05-15 16:34:17 +03:00
|
|
|
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
ValidateChecksumHeader::ValidateChecksumHeader(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
2015-05-15 16:34:17 +03:00
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
void ValidateChecksumHeader::start(const QString& filePath, const QByteArray& checksumHeader)
|
2015-05-15 16:34:17 +03:00
|
|
|
{
|
2015-10-14 16:03:40 +03:00
|
|
|
// If the incoming header is empty no validation can happen. Just continue.
|
2015-10-14 14:41:51 +03:00
|
|
|
if( checksumHeader.isEmpty() ) {
|
2015-05-21 16:51:48 +03:00
|
|
|
emit validated(QByteArray());
|
2015-05-15 16:34:17 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
if( !parseChecksumHeader(checksumHeader, &_expectedChecksumType, &_expectedChecksum) ) {
|
2015-05-15 16:34:17 +03:00
|
|
|
qDebug() << "Checksum header malformed:" << checksumHeader;
|
2015-05-19 17:49:22 +03:00
|
|
|
emit validationFailed(tr("The checksum header is malformed."));
|
|
|
|
return;
|
2015-05-15 16:34:17 +03:00
|
|
|
}
|
2015-10-14 16:03:40 +03:00
|
|
|
|
|
|
|
auto calculator = new ComputeChecksum(this);
|
|
|
|
calculator->setChecksumType(_expectedChecksumType);
|
|
|
|
connect(calculator, SIGNAL(done(QByteArray,QByteArray)),
|
|
|
|
SLOT(slotChecksumCalculated(QByteArray,QByteArray)));
|
|
|
|
calculator->start(filePath);
|
2015-05-15 16:34:17 +03:00
|
|
|
}
|
|
|
|
|
2015-10-14 16:03:40 +03:00
|
|
|
void ValidateChecksumHeader::slotChecksumCalculated(const QByteArray& checksumType,
|
|
|
|
const QByteArray& checksum)
|
2015-05-15 16:34:17 +03:00
|
|
|
{
|
2015-10-14 16:03:40 +03:00
|
|
|
if( checksumType != _expectedChecksumType ) {
|
|
|
|
emit validationFailed(tr("The checksum header contained an unknown checksum type '%1'").arg(
|
|
|
|
QString::fromLatin1(_expectedChecksumType)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( checksum != _expectedChecksum ) {
|
2015-05-19 17:49:22 +03:00
|
|
|
emit validationFailed(tr("The downloaded file does not match the checksum, it will be resumed."));
|
2015-10-14 16:03:40 +03:00
|
|
|
return;
|
2015-05-15 16:34:17 +03:00
|
|
|
}
|
2015-10-14 16:03:40 +03:00
|
|
|
emit validated(makeChecksumHeader(checksumType, checksum));
|
2015-05-15 16:34:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|