nextcloud-desktop/src/gui/syncrunfilelog.cpp

216 lines
6.6 KiB
C++
Raw Normal View History

/*
* 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 <QRegExp>
#include "syncrunfilelog.h"
#include "common/utility.h"
2014-04-02 18:36:32 +04:00
#include "filesystem.h"
2014-03-28 13:13:35 +04:00
#include <qfileinfo.h>
2014-11-10 00:34:07 +03:00
namespace OCC {
SyncRunFileLog::SyncRunFileLog() = default;
2017-05-17 11:55:42 +03:00
QString SyncRunFileLog::dateTimeStr(const QDateTime &dt)
{
return dt.toString(Qt::ISODate);
}
2017-05-17 11:55:42 +03:00
QString SyncRunFileLog::directionToStr(SyncFileItem::Direction dir)
{
QString re("N");
2017-05-17 11:55:42 +03:00
if (dir == SyncFileItem::Up) {
re = QLatin1String("Up");
2017-05-17 11:55:42 +03:00
} else if (dir == SyncFileItem::Down) {
re = QLatin1String("Down");
}
return re;
}
2017-05-17 11:55:42 +03:00
QString SyncRunFileLog::instructionToStr(csync_instructions_e inst)
{
QString re;
2017-05-17 11:55:42 +03:00
switch (inst) {
case CSYNC_INSTRUCTION_NONE:
re = "INST_NONE";
break;
case CSYNC_INSTRUCTION_EVAL:
re = "INST_EVAL";
break;
case CSYNC_INSTRUCTION_REMOVE:
re = "INST_REMOVE";
break;
case CSYNC_INSTRUCTION_RENAME:
re = "INST_RENAME";
break;
case CSYNC_INSTRUCTION_EVAL_RENAME:
re = "INST_EVAL_RENAME";
break;
case CSYNC_INSTRUCTION_NEW:
re = "INST_NEW";
break;
case CSYNC_INSTRUCTION_CONFLICT:
re = "INST_CONFLICT";
break;
case CSYNC_INSTRUCTION_IGNORE:
re = "INST_IGNORE";
break;
case CSYNC_INSTRUCTION_SYNC:
re = "INST_SYNC";
break;
case CSYNC_INSTRUCTION_STAT_ERROR:
re = "INST_STAT_ERR";
break;
case CSYNC_INSTRUCTION_ERROR:
re = "INST_ERROR";
break;
case CSYNC_INSTRUCTION_TYPE_CHANGE:
re = "INST_TYPE_CHANGE";
break;
csync: Use an explicit instruction for should_update_metadata The current way of tracking the need to update the metadata without propagation using a separate flag makes it difficult to track priorities between the local and remote tree. The logic is also difficult to logically cover since the possibilities matrix isn't 100% covered, leaving the flag only used in a few situations (mostly involving folders, but not only). The reason we need to change this is to be able to track the sync state of files for overlay icons. The instruction alone can't be used since CSYNC_INSTRUCTION_SYNC is used for folders even though they won't be propagated. Removing this logic is however not possible without using something else than CSYNC_INSTRUCTION_NONE since too many codepath interpret (rightfully) this as meaning "nothing to do". This patch adds a new CSYNC_INSTRUCTION_UPDATE_METADATA instruction to let the update and reconcile steps tell the SyncEngine to update the metadata of a file without any propagation. Other flags are left to be interpretted by the implementation as implicitly needing metadata update or not, as this was already the case for most file propagation jobs. For example, CSYNC_INSTRUCTION_NEW for directories now also implicitly update the metadata. Since it's not impossible for folders to emit CSYNC_INSTRUCTION_SYNC or CSYNC_INSTRUCTION_CONFLICT, the corresponding code paths in the sync engine have been removed. Since the reconcile step can now know if the local tree needs metadata update while the remote side might want propagation, the localMetadataUpdate logic in SyncEngine::treewalkFile now simply use a CSYNC_INSTRUCTION_UPDATE_METADATA for the local side, which is now implemented as a different database query.
2016-08-15 15:17:51 +03:00
case CSYNC_INSTRUCTION_UPDATE_METADATA:
re = "INST_METADATA";
break;
}
return re;
}
void SyncRunFileLog::start(const QString &folderPath)
{
2018-05-24 17:02:52 +03:00
const qint64 logfileMaxSize = 10 * 1024 * 1024; // 10MiB
2018-04-30 17:09:04 +03:00
const QString logpath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if(!QDir(logpath).exists()) {
QDir().mkdir(logpath);
2018-04-17 16:54:05 +03:00
}
2018-05-24 17:02:52 +03:00
2018-04-30 17:09:04 +03:00
int length = folderPath.split(QLatin1String("/")).length();
QString filenameSingle = folderPath.split(QLatin1String("/")).at(length - 2);
QString filename = logpath + QLatin1String("/") + filenameSingle + QLatin1String("_sync.log");
2018-05-24 17:02:52 +03:00
2018-04-30 17:09:04 +03:00
int depthIndex = 2;
while(QFile::exists(filename)) {
2018-05-24 17:02:52 +03:00
2018-04-30 17:09:04 +03:00
QFile file(filename);
file.open(QIODevice::ReadOnly| QIODevice::Text);
QTextStream in(&file);
QString line = in.readLine();
2018-05-24 17:02:52 +03:00
2018-04-30 17:09:04 +03:00
if(QString::compare(folderPath,line,Qt::CaseSensitive)!=0) {
depthIndex++;
if(depthIndex <= length) {
filenameSingle = folderPath.split(QLatin1String("/")).at(length - depthIndex) + QString("_") ///
+ filenameSingle;
filename = logpath+ QLatin1String("/") + filenameSingle + QLatin1String("_sync.log");
}
else {
filenameSingle = filenameSingle + QLatin1String("_1");
filename = logpath + QLatin1String("/") + filenameSingle + QLatin1String("_sync.log");
}
}
else break;
2018-04-24 16:47:23 +03:00
}
2018-05-24 17:02:52 +03:00
2014-03-28 13:13:35 +04:00
// When the file is too big, just rename it to an old name.
QFileInfo info(filename);
bool exists = info.exists();
if (exists && info.size() > logfileMaxSize) {
exists = false;
2014-03-28 13:13:35 +04:00
QString newFilename = filename + QLatin1String(".1");
QFile::remove(newFilename);
QFile::rename(filename, newFilename);
}
_file.reset(new QFile(filename));
2018-05-24 17:02:52 +03:00
_file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
2017-05-17 11:55:42 +03:00
_out.setDevice(_file.data());
2018-05-24 17:02:52 +03:00
if (!exists) {
_out << folderPath << endl;
// We are creating a new file, add the note.
_out << "# timestamp | duration | file | instruction | dir | modtime | etag | "
"size | fileId | status | errorString | http result code | "
"other size | other modtime | other etag | other fileId | "
2017-05-17 11:55:42 +03:00
"other instruction"
<< endl;
2018-05-24 17:02:52 +03:00
2014-04-02 18:36:32 +04:00
FileSystem::setFileHidden(filename, true);
}
2018-05-24 17:02:52 +03:00
_totalDuration.start();
_lapDuration.start();
_out << "#=#=#=# Syncrun started " << dateTimeStr(QDateTime::currentDateTimeUtc()) << endl;
}
2017-05-17 11:55:42 +03:00
void SyncRunFileLog::logItem(const SyncFileItem &item)
{
// don't log the directory items that are in the list
if (item._direction == SyncFileItem::None
|| item._instruction == CSYNC_INSTRUCTION_IGNORE) {
return;
}
QString ts = QString::fromLatin1(item._responseTimeStamp);
2017-05-17 11:55:42 +03:00
if (ts.length() > 6) {
QRegExp rx(R"((\d\d:\d\d:\d\d))");
2017-05-17 11:55:42 +03:00
if (ts.contains(rx)) {
ts = rx.cap(0);
}
}
const QChar L = QLatin1Char('|');
_out << ts << L;
_out << L;
2017-05-17 11:55:42 +03:00
if (item._instruction != CSYNC_INSTRUCTION_RENAME) {
_out << item._file << L;
} else {
_out << item._file << QLatin1String(" -> ") << item._renameTarget << L;
}
2017-05-17 11:55:42 +03:00
_out << instructionToStr(item._instruction) << L;
_out << directionToStr(item._direction) << L;
_out << QString::number(item._modtime) << L;
_out << item._etag << L;
_out << QString::number(item._size) << L;
_out << item._fileId << L;
_out << item._status << L;
_out << item._errorString << L;
_out << QString::number(item._httpErrorCode) << L;
_out << QString::number(item._previousSize) << L;
_out << QString::number(item._previousModtime) << L;
_out /* << other etag (removed) */ << L;
_out /* << other fileId (removed) */ << L;
_out /* << other instruction (removed) */ << L;
_out << endl;
}
2017-05-17 11:55:42 +03:00
void SyncRunFileLog::logLap(const QString &name)
{
_out << "#=#=#=#=# " << name << " " << dateTimeStr(QDateTime::currentDateTimeUtc())
<< " (last step: " << _lapDuration.restart() << " msec"
<< ", total: " << _totalDuration.elapsed() << " msec)" << endl;
}
void SyncRunFileLog::finish()
{
_out << "#=#=#=# Syncrun finished " << dateTimeStr(QDateTime::currentDateTimeUtc())
<< " (last step: " << _lapDuration.elapsed() << " msec"
<< ", total: " << _totalDuration.elapsed() << " msec)" << endl;
_file->close();
}
}