#include "utility.h"
#include "filesystem.h"
#include "propagatorjobs.h"
+#include "configfile.h"
+
#include <json.h>
#include <QNetworkAccessManager>
#include <QFileInfo>
#include <QDir>
#include <cmath>
#include <cstring>
+#include <QtConcurrent>
#ifdef USE_NEON
#include "propagator_legacy.h"
namespace OCC {
+/**
+ * Tags for checksum headers.
+ */
+static const char checkSumMD5C[] = "MD5";
+static const char checkSumSHA1C[] = "SHA1";
+static const char checkSumAdlerC[] = "Adler32";
+static const char checkSumAdlerUpperC[] = "ADLER32";
+
/**
* We do not want to upload files that are currently being modified.
* To avoid that, we don't upload files that have a modification time
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
return;
}
+ ConfigFile cfg; // FIXME: Do not open it for each and every propagation.
+
+ const QString filePath = _propagator->getFilePath(_item._file);
+ _item._modtime = FileSystem::getModTime(filePath);
+ // calculate the files checksum
+ const QString transChecksum = cfg.transmissionChecksum();
+ _stopWatch.start();
+
+ if( transChecksum.isEmpty() ) {
+ // no checksumming required, jump to really start the uplaod
+ startUpload();
+ } else {
+ // Calculate the checksum in a different thread first.
+ connect( &_watcher, SIGNAL(finished()),
+ this, SLOT(slotChecksumCalculated()));
+ bool haveFuture = true;
+ if( transChecksum == checkSumMD5C ) {
+ _item._checksum = checkSumMD5C;
+ _item._checksum += ":";
+ _watcher.setFuture(QtConcurrent::run(FileSystem::calcMd5Worker,filePath));
+
+ } else if( transChecksum == checkSumSHA1C ) {
+ _item._checksum = checkSumSHA1C;
+ _item._checksum += ":";
+ _watcher.setFuture(QtConcurrent::run( FileSystem::calcSha1Worker, filePath));
+ }
+#ifdef ZLIB_FOUND
+ else if( transChecksum == checkSumAdlerC) {
+ _item._checksum = checkSumAdlerC;
+ _item._checksum += ":";
+ _watcher.setFuture(QtConcurrent::run(FileSystem::calcAdler32Worker, filePath));
+ }
+#endif
+ else {
+ haveFuture = false;
+ }
+ // in case there is a wrong checksum header, let continue without
+ if( !haveFuture ) {
+ startUpload();
+ }
+ }
+
+}
+
+void PropagateUploadFileQNAM::slotChecksumCalculated( )
+{
+ QByteArray checksum = _watcher.future().result();
+
+ if( !checksum.isEmpty() ) {
+ _item._checksum.append(checksum);
+ } else {
+ _item._checksum.clear();
+ }
+
+ startUpload();
+}
+
+void PropagateUploadFileQNAM::startUpload()
+{
const QString fullFilePath(_propagator->getFilePath(_item._file));
if (!FileSystem::fileExists(fullFilePath)) {
done(SyncFileItem::SoftError, tr("File Removed"));
return;
}
+ _stopWatch.addLapTime(QLatin1String("Checksum"));
+
+ // Update the mtime and size, it might have changed since discovery.
+ time_t prevModtime = _item._modtime; // the value was set in PropagateUploadFileQNAM::start()
+ // but a potential checksum calculation could have taken some time during which the file could
+ // have been changed again, so better check again here.
// Update the mtime and size, it might have changed since discovery.
_item._modtime = FileSystem::getModTime(fullFilePath);
+ if( prevModtime != _item._modtime ) {
+ _propagator->_anotherSyncNeeded = true;
+ done(SyncFileItem::SoftError, tr("Local filei changed while calculating the checksum."));
+ return;
+ }
+
quint64 fileSize = FileSystem::getSize(fullFilePath);
_item._size = fileSize;
if( currentChunkSize == 0 ) { // if the last chunk pretents to be 0, its actually the full chunk size.
currentChunkSize = chunkSize();
}
+ if( !_item._checksum.isEmpty() ) {
+ headers["OC-Checksum"] = _item._checksum;
+ }
}
}
// Well, the mtime was not set
#endif
}
+
+ // performance logging
+ _item._requestDuration = _stopWatch.stop();
+ qDebug() << "*==* duration UPLOAD" << _item._size << _stopWatch.durationOfLap(QLatin1String("Checksum")) << _item._requestDuration;
+
finalize(_item);
}
#include <QBuffer>
#include <QFile>
#include <QDebug>
+#include <QFutureWatcher>
+
namespace OCC {
class BandwidthManager;
class PUTFileJob : public AbstractNetworkJob {
Q_OBJECT
+
+private:
QScopedPointer<QIODevice> _device;
QMap<QByteArray, QByteArray> _headers;
QString _errorString;
class PropagateUploadFileQNAM : public PropagateItemJob {
Q_OBJECT
+private:
/**
* That's the start chunk that was stored in the database for resuming.
* In the non-resuming case it is 0.
QElapsedTimer _duration;
QVector<PUTFileJob*> _jobs; /// network jobs that are currently in transit
bool _finished; // Tells that all the jobs have been finished
+
+ // watcher for the checksum calculation thread
+ QFutureWatcher<QByteArray> _watcher;
+
+ // measure the performance of checksum calc and upload
+ Utility::StopWatch _stopWatch;
public:
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false) {}
void startNextChunk();
void finalize(const SyncFileItem&);
void slotJobDestroyed(QObject *job);
+ void startUpload();
+ void slotChecksumCalculated();
private:
void startPollJob(const QString& path);
void abortWithError(SyncFileItem::Status status, const QString &error);