mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Move the SocketApi business logic to a libsync SyncFileStatusTracker class
This will allow testing this code and avoid going through too many layers to get notified and a file status changed.
This commit is contained in:
parent
dac4bd8370
commit
da7b9916e5
@ -34,6 +34,7 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
#include <QListWidgetItem>
|
||||
#include <QMessageBox>
|
||||
#include <QAction>
|
||||
|
||||
@ -99,8 +99,6 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
connect(_engine.data(), SIGNAL(rootEtag(QString)), this, SLOT(etagRetreivedFromSyncEngine(QString)));
|
||||
connect(_engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||
this, SLOT(slotAboutToPropagate(SyncFileItemVector&)));
|
||||
|
||||
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
|
||||
connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection);
|
||||
@ -595,71 +593,11 @@ void Folder::slotWatchedPathChanged(const QString& path)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this item should get an ERROR icon through the Socket API.
|
||||
*
|
||||
* The Socket API should only present serious, permanent errors to the user.
|
||||
* In particular SoftErrors should just retain their 'needs to be synced'
|
||||
* icon as the problem is most likely going to resolve itself quickly and
|
||||
* automatically.
|
||||
*/
|
||||
static bool showErrorInSocketApi(const SyncFileItem& item)
|
||||
{
|
||||
const auto status = item._status;
|
||||
return status == SyncFileItem::NormalError
|
||||
|| status == SyncFileItem::FatalError;
|
||||
}
|
||||
|
||||
static void addErroredSyncItemPathsToList(const SyncFileItemVector& items, QSet<QString>* set) {
|
||||
foreach (const SyncFileItemPtr &item, items) {
|
||||
if (showErrorInSocketApi(*item)) {
|
||||
set->insert(item->_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
{
|
||||
addErroredSyncItemPathsToList(items, &this->_stateLastSyncItemsWithErrorNew);
|
||||
_syncResult.setSyncFileItemVector(items);
|
||||
}
|
||||
|
||||
void Folder::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
{
|
||||
addErroredSyncItemPathsToList(items, &this->_stateLastSyncItemsWithErrorNew);
|
||||
}
|
||||
|
||||
|
||||
bool Folder::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s)
|
||||
{
|
||||
if (t == CSYNC_FTW_TYPE_DIR) {
|
||||
if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) {
|
||||
qDebug() << Q_FUNC_INFO << "Folder has error" << fn;
|
||||
s->set(SyncFileStatus::STATUS_ERROR);
|
||||
return true;
|
||||
}
|
||||
// If sync is running, check _syncedItems, possibly give it STATUS_EVAL (=syncing down)
|
||||
if (_engine->isSyncRunning()) {
|
||||
if (_engine->estimateState(fn, t, s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if ( t== CSYNC_FTW_TYPE_FILE) {
|
||||
// check if errorList has the directory/file
|
||||
if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) {
|
||||
s->set(SyncFileStatus::STATUS_ERROR);
|
||||
return true;
|
||||
}
|
||||
// If sync running: _syncedItems -> SyncingState
|
||||
if (_engine->isSyncRunning()) {
|
||||
if (_engine->estimateState(fn, t, s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Folder::saveToSettings() const
|
||||
{
|
||||
@ -873,10 +811,6 @@ void Folder::slotSyncFinished(bool success)
|
||||
|
||||
|
||||
|
||||
// This is for sync state calculation
|
||||
_stateLastSyncItemsWithError = _stateLastSyncItemsWithErrorNew;
|
||||
_stateLastSyncItemsWithErrorNew.clear();
|
||||
|
||||
if (_csyncError) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
qDebug() << " ** error Strings: " << _errors;
|
||||
@ -972,10 +906,6 @@ void Folder::slotTransmissionProgress(const ProgressInfo &pi)
|
||||
// a item is completed: count the errors and forward to the ProgressDispatcher
|
||||
void Folder::slotItemCompleted(const SyncFileItem &item, const PropagatorJob& job)
|
||||
{
|
||||
if (showErrorInSocketApi(item)) {
|
||||
_stateLastSyncItemsWithErrorNew.insert(item._file);
|
||||
}
|
||||
|
||||
if (Progress::isWarningKind(item._status)) {
|
||||
// Count all error conditions.
|
||||
_syncResult.setWarnCount(_syncResult.warnCount()+1);
|
||||
|
||||
@ -26,16 +26,9 @@
|
||||
|
||||
#include <csync.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <qelapsedtimer.h>
|
||||
|
||||
class QThread;
|
||||
class QSettings;
|
||||
|
||||
@ -181,8 +174,7 @@ public:
|
||||
|
||||
// Used by the Socket API
|
||||
SyncJournalDb *journalDb() { return &_journal; }
|
||||
|
||||
bool estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s);
|
||||
SyncEngine &syncEngine() { return *_engine; }
|
||||
|
||||
RequestEtagJob *etagJob() { return _requestEtagJob; }
|
||||
qint64 msecSinceLastSync() const { return _timeSinceLastSyncDone.elapsed(); }
|
||||
@ -262,7 +254,6 @@ private slots:
|
||||
void etagRetreived(const QString &);
|
||||
void etagRetreivedFromSyncEngine(const QString &);
|
||||
|
||||
void slotAboutToPropagate(SyncFileItemVector& );
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done
|
||||
|
||||
void slotEmitFinishedDelayed();
|
||||
@ -304,15 +295,6 @@ private:
|
||||
/// Reset when no follow-up is requested.
|
||||
int _consecutiveFollowUpSyncs;
|
||||
|
||||
// SocketAPI: Cache files and folders that had errors so that they can
|
||||
// get a red ERROR icon.
|
||||
QSet<QString> _stateLastSyncItemsWithErrorNew; // gets moved to _stateLastSyncItemsWithError at end of sync
|
||||
QSet<QString> _stateLastSyncItemsWithError;
|
||||
|
||||
// SocketAPI: A folder is tained if we got a file watcher notification
|
||||
// for it. It's displayed as EVAL.
|
||||
QSet<QString> _stateTaintedFolders;
|
||||
|
||||
SyncJournalDb _journal;
|
||||
|
||||
ClientProxy _clientProxy;
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "utility.h"
|
||||
#include "theme.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "syncengine.h"
|
||||
#include "syncfileitem.h"
|
||||
#include "filesystem.h"
|
||||
#include "version.h"
|
||||
@ -215,7 +216,7 @@ void SocketApi::slotUpdateFolderView(Folder *f)
|
||||
f->syncResult().status() == SyncResult::SetupError ) {
|
||||
|
||||
broadcastMessage(QLatin1String("STATUS"), f->path() ,
|
||||
this->fileStatus(f, "").toSocketAPIString());
|
||||
f->syncEngine().syncFileStatusTracker().fileStatus("").toSocketAPIString());
|
||||
|
||||
broadcastMessage(QLatin1String("UPDATE_VIEW"), f->path() );
|
||||
} else {
|
||||
@ -235,7 +236,7 @@ void SocketApi::slotItemCompleted(const QString &folder, const SyncFileItem &ite
|
||||
return;
|
||||
}
|
||||
|
||||
auto status = this->fileStatus(f, item.destination());
|
||||
auto status = f->syncEngine().syncFileStatusTracker().fileStatus(item.destination());
|
||||
const QString path = f->path() + item.destination();
|
||||
broadcastMessage(QLatin1String("STATUS"), path, status.toSocketAPIString());
|
||||
}
|
||||
@ -330,7 +331,7 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice*
|
||||
statusString = QLatin1String("NOP");
|
||||
} else {
|
||||
const QString file = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1);
|
||||
SyncFileStatus fileStatus = this->fileStatus(syncFolder, file);
|
||||
SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(file);
|
||||
|
||||
statusString = fileStatus.toSocketAPIString();
|
||||
}
|
||||
@ -367,7 +368,7 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
|
||||
} else {
|
||||
const QString localFileClean = QDir::cleanPath(localFile);
|
||||
const QString file = localFileClean.mid(shareFolder->cleanPath().length()+1);
|
||||
SyncFileStatus fileStatus = this->fileStatus(shareFolder, file);
|
||||
SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file);
|
||||
|
||||
// Verify the file is on the server (to our knowledge of course)
|
||||
if (fileStatus.tag() != SyncFileStatus::STATUS_UPTODATE &&
|
||||
@ -423,7 +424,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
|
||||
sendMessage(socket, message);
|
||||
} else {
|
||||
const QString file = QDir::cleanPath(localFile).mid(shareFolder->cleanPath().length()+1);
|
||||
SyncFileStatus fileStatus = this->fileStatus(shareFolder, file);
|
||||
SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file);
|
||||
|
||||
// Verify the file is on the server (to our knowledge of course)
|
||||
if (fileStatus.tag() != SyncFileStatus::STATUS_UPTODATE &&
|
||||
@ -478,142 +479,4 @@ QString SocketApi::buildRegisterPathMessage(const QString& path)
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status about a single file.
|
||||
*/
|
||||
SyncFileStatus SocketApi::fileStatus(Folder *folder, const QString& systemFileName)
|
||||
{
|
||||
QString file = folder->path();
|
||||
QString fileName = systemFileName.normalized(QString::NormalizationForm_C);
|
||||
QString fileNameSlash = fileName;
|
||||
|
||||
if(fileName != QLatin1String("/") && !fileName.isEmpty()) {
|
||||
file += fileName;
|
||||
}
|
||||
|
||||
if( fileName.endsWith(QLatin1Char('/')) ) {
|
||||
fileName.truncate(fileName.length()-1);
|
||||
qDebug() << "Removed trailing slash: " << fileName;
|
||||
} else {
|
||||
fileNameSlash += QLatin1Char('/');
|
||||
}
|
||||
|
||||
const QFileInfo fi(file);
|
||||
if( !FileSystem::fileExists(file, fi) ) {
|
||||
qDebug() << "OO File " << file << " is not existing";
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_STAT_ERROR);
|
||||
}
|
||||
|
||||
// file is ignored?
|
||||
// Qt considers .lnk files symlinks on Windows so we need to work
|
||||
// around that here.
|
||||
if( fi.isSymLink()
|
||||
#ifdef Q_OS_WIN
|
||||
&& fi.suffix() != "lnk"
|
||||
#endif
|
||||
) {
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_IGNORE);
|
||||
}
|
||||
|
||||
csync_ftw_type_e type = CSYNC_FTW_TYPE_FILE;
|
||||
if( fi.isDir() ) {
|
||||
type = CSYNC_FTW_TYPE_DIR;
|
||||
}
|
||||
|
||||
// Is it excluded?
|
||||
if( folder->isFileExcludedRelative(fileName) ) {
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_IGNORE);
|
||||
}
|
||||
|
||||
// Error if it is in the selective sync blacklist
|
||||
foreach(const auto &s, folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList)) {
|
||||
if (fileNameSlash.startsWith(s)) {
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
SyncFileStatus status(SyncFileStatus::STATUS_NONE);
|
||||
SyncJournalFileRecord rec = folder->journalDb()->getFileRecord(fileName);
|
||||
|
||||
if (folder->estimateState(fileName, type, &status)) {
|
||||
qDebug() << "Folder estimated status for" << fileName << "to" << status.toSocketAPIString();
|
||||
} else if (fileName == "") {
|
||||
// sync folder itself
|
||||
switch (folder->syncResult().status()) {
|
||||
case SyncResult::Undefined:
|
||||
case SyncResult::NotYetStarted:
|
||||
case SyncResult::SyncPrepare:
|
||||
case SyncResult::SyncRunning:
|
||||
status.set(SyncFileStatus::STATUS_EVAL);
|
||||
return status;
|
||||
|
||||
case SyncResult::Success:
|
||||
case SyncResult::Problem:
|
||||
status.set(SyncFileStatus::STATUS_UPTODATE);
|
||||
return status;
|
||||
|
||||
case SyncResult::Error:
|
||||
case SyncResult::SetupError:
|
||||
case SyncResult::SyncAbortRequested:
|
||||
status.set(SyncFileStatus::STATUS_ERROR);
|
||||
return status;
|
||||
|
||||
case SyncResult::Paused:
|
||||
status.set(SyncFileStatus::STATUS_IGNORE);
|
||||
return status;
|
||||
}
|
||||
} else if (type == CSYNC_FTW_TYPE_DIR) {
|
||||
if (rec.isValid()) {
|
||||
status.set(SyncFileStatus::STATUS_UPTODATE);
|
||||
} else {
|
||||
qDebug() << "Could not determine state for folder" << fileName << "will set STATUS_NEW";
|
||||
status.set(SyncFileStatus::STATUS_NEW);
|
||||
}
|
||||
} else if (type == CSYNC_FTW_TYPE_FILE) {
|
||||
if (rec.isValid()) {
|
||||
if( FileSystem::getModTime(fi.absoluteFilePath()) == Utility::qDateTimeToTime_t(rec._modtime) ) {
|
||||
status.set(SyncFileStatus::STATUS_UPTODATE);
|
||||
} else {
|
||||
if (rec._remotePerm.isNull() || rec._remotePerm.contains("W") ) {
|
||||
status.set(SyncFileStatus::STATUS_EVAL);
|
||||
} else {
|
||||
status.set(SyncFileStatus::STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Could not determine state for file" << fileName << "will set STATUS_NEW";
|
||||
status.set(SyncFileStatus::STATUS_NEW);
|
||||
}
|
||||
}
|
||||
|
||||
if (rec.isValid() && rec._remotePerm.contains("S"))
|
||||
status.setSharedWithMe(true);
|
||||
|
||||
if (status.tag() == SyncFileStatus::STATUS_NEW) {
|
||||
// check the parent folder if it is shared and if it is allowed to create a file/dir within
|
||||
QDir d( fi.path() );
|
||||
auto parentPath = d.path();
|
||||
auto dirRec = folder->journalDb()->getFileRecord(parentPath);
|
||||
bool isDir = type == CSYNC_FTW_TYPE_DIR;
|
||||
while( !d.isRoot() && !(d.exists() && dirRec.isValid()) ) {
|
||||
d.cdUp(); // returns true if the dir exists.
|
||||
|
||||
parentPath = d.path();
|
||||
// cut the folder path
|
||||
dirRec = folder->journalDb()->getFileRecord(parentPath);
|
||||
|
||||
isDir = true;
|
||||
}
|
||||
if( dirRec.isValid() && !dirRec._remotePerm.isNull()) {
|
||||
if( (isDir && !dirRec._remotePerm.contains("K"))
|
||||
|| (!isDir && !dirRec._remotePerm.contains("C")) ) {
|
||||
status.set(SyncFileStatus::STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
|
||||
@ -56,6 +56,7 @@ set(libsync_SRCS
|
||||
propagateremotemkdir.cpp
|
||||
syncengine.cpp
|
||||
syncfilestatus.cpp
|
||||
syncfilestatustracker.cpp
|
||||
syncjournaldb.cpp
|
||||
syncjournalfilerecord.cpp
|
||||
syncresult.cpp
|
||||
|
||||
@ -93,6 +93,7 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
|
||||
csync_create(&_csync_ctx, localPath.toUtf8().data(), url_string.toUtf8().data());
|
||||
csync_init(_csync_ctx);
|
||||
_excludedFiles.reset(new ExcludedFiles(&_csync_ctx->excludes));
|
||||
_syncFileStatusTracker.reset(new SyncFileStatusTracker(this));
|
||||
|
||||
_thread.setObjectName("SyncEngine_Thread");
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
#include "syncfileitem.h"
|
||||
#include "progressdispatcher.h"
|
||||
#include "utility.h"
|
||||
#include "syncfilestatus.h"
|
||||
#include "syncfilestatustracker.h"
|
||||
#include "accountfwd.h"
|
||||
#include "discoveryphase.h"
|
||||
#include "checksums.h"
|
||||
@ -75,10 +75,12 @@ public:
|
||||
* -1 means infinite
|
||||
*/
|
||||
void setNewBigFolderSizeLimit(qint64 limit) { _newBigFolderSizeLimit = limit; }
|
||||
bool ignoreHiddenFiles() const { return _csync_ctx->ignore_hidden_files; }
|
||||
void setIgnoreHiddenFiles(bool ignore) { _csync_ctx->ignore_hidden_files = ignore; }
|
||||
|
||||
ExcludedFiles &excludedFiles() { return *_excludedFiles; }
|
||||
Utility::StopWatch &stopWatch() { return _stopWatch; }
|
||||
SyncFileStatusTracker &syncFileStatusTracker() { return *_syncFileStatusTracker; }
|
||||
|
||||
/* Return true if we detected that another sync is needed to complete the sync */
|
||||
bool isAnotherSyncNeeded() { return _anotherSyncNeeded; }
|
||||
@ -93,7 +95,7 @@ public:
|
||||
|
||||
AccountPtr account() const;
|
||||
SyncJournalDb *journal() const { return _journal; }
|
||||
|
||||
QString localPath() const { return _localPath; }
|
||||
/**
|
||||
* Minimum age, in milisecond, of a file that can be uploaded.
|
||||
* Files more recent than that are not going to be uploaeded as they are considered
|
||||
@ -211,6 +213,7 @@ private:
|
||||
QScopedPointer<ProgressInfo> _progressInfo;
|
||||
|
||||
QScopedPointer<ExcludedFiles> _excludedFiles;
|
||||
QScopedPointer<SyncFileStatusTracker> _syncFileStatusTracker;
|
||||
Utility::StopWatch _stopWatch;
|
||||
|
||||
// maps the origin and the target of the folders that have been renamed
|
||||
|
||||
230
src/libsync/syncfilestatustracker.cpp
Normal file
230
src/libsync/syncfilestatustracker.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 "syncfilestatustracker.h"
|
||||
#include "filesystem.h"
|
||||
#include "syncengine.h"
|
||||
#include "syncjournaldb.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
/**
|
||||
* Whether this item should get an ERROR icon through the Socket API.
|
||||
*
|
||||
* The Socket API should only present serious, permanent errors to the user.
|
||||
* In particular SoftErrors should just retain their 'needs to be synced'
|
||||
* icon as the problem is most likely going to resolve itself quickly and
|
||||
* automatically.
|
||||
*/
|
||||
static bool showErrorInSocketApi(const SyncFileItem& item)
|
||||
{
|
||||
const auto status = item._status;
|
||||
return status == SyncFileItem::NormalError
|
||||
|| status == SyncFileItem::FatalError;
|
||||
}
|
||||
|
||||
static void addErroredSyncItemPathsToList(const SyncFileItemVector& items, QSet<QString>* set) {
|
||||
foreach (const SyncFileItemPtr &item, items) {
|
||||
if (showErrorInSocketApi(*item)) {
|
||||
set->insert(item->_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SyncFileStatusTracker::SyncFileStatusTracker(SyncEngine *syncEngine)
|
||||
: _syncEngine(syncEngine)
|
||||
{
|
||||
connect(syncEngine, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)));
|
||||
connect(syncEngine, SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||
this, SLOT(slotAboutToPropagate(SyncFileItemVector&)));
|
||||
connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncFinished()));
|
||||
connect(syncEngine, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &)));
|
||||
}
|
||||
|
||||
bool SyncFileStatusTracker::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s)
|
||||
{
|
||||
if (t == CSYNC_FTW_TYPE_DIR) {
|
||||
if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) {
|
||||
qDebug() << Q_FUNC_INFO << "Folder has error" << fn;
|
||||
s->set(SyncFileStatus::STATUS_ERROR);
|
||||
return true;
|
||||
}
|
||||
// If sync is running, check _syncedItems, possibly give it STATUS_EVAL (=syncing down)
|
||||
if (_syncEngine->isSyncRunning()) {
|
||||
if (_syncEngine->estimateState(fn, t, s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if ( t== CSYNC_FTW_TYPE_FILE) {
|
||||
// check if errorList has the directory/file
|
||||
if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) {
|
||||
s->set(SyncFileStatus::STATUS_ERROR);
|
||||
return true;
|
||||
}
|
||||
// If sync running: _syncedItems -> SyncingState
|
||||
if (_syncEngine->isSyncRunning()) {
|
||||
if (_syncEngine->estimateState(fn, t, s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get status about a single file.
|
||||
*/
|
||||
SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& systemFileName)
|
||||
{
|
||||
QString file = _syncEngine->localPath();
|
||||
QString fileName = systemFileName.normalized(QString::NormalizationForm_C);
|
||||
QString fileNameSlash = fileName;
|
||||
|
||||
if(fileName != QLatin1String("/") && !fileName.isEmpty()) {
|
||||
file += fileName;
|
||||
}
|
||||
|
||||
if( fileName.endsWith(QLatin1Char('/')) ) {
|
||||
fileName.truncate(fileName.length()-1);
|
||||
qDebug() << "Removed trailing slash: " << fileName;
|
||||
} else {
|
||||
fileNameSlash += QLatin1Char('/');
|
||||
}
|
||||
|
||||
const QFileInfo fi(file);
|
||||
if( !FileSystem::fileExists(file, fi) ) {
|
||||
qDebug() << "OO File " << file << " is not existing";
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_STAT_ERROR);
|
||||
}
|
||||
|
||||
// file is ignored?
|
||||
// Qt considers .lnk files symlinks on Windows so we need to work
|
||||
// around that here.
|
||||
if( fi.isSymLink()
|
||||
#ifdef Q_OS_WIN
|
||||
&& fi.suffix() != "lnk"
|
||||
#endif
|
||||
) {
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_IGNORE);
|
||||
}
|
||||
|
||||
csync_ftw_type_e type = CSYNC_FTW_TYPE_FILE;
|
||||
if( fi.isDir() ) {
|
||||
type = CSYNC_FTW_TYPE_DIR;
|
||||
}
|
||||
|
||||
// Is it excluded?
|
||||
if( _syncEngine->excludedFiles().isExcluded(file, _syncEngine->localPath(), _syncEngine->ignoreHiddenFiles()) ) {
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_IGNORE);
|
||||
}
|
||||
|
||||
// Error if it is in the selective sync blacklist
|
||||
foreach(const auto &s, _syncEngine->journal()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList)) {
|
||||
if (fileNameSlash.startsWith(s)) {
|
||||
return SyncFileStatus(SyncFileStatus::STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
SyncFileStatus status(SyncFileStatus::STATUS_NONE);
|
||||
SyncJournalFileRecord rec = _syncEngine->journal()->getFileRecord(fileName );
|
||||
|
||||
if (estimateState(fileName, type, &status)) {
|
||||
qDebug() << "Folder estimated status for" << fileName << "to" << status.toSocketAPIString();
|
||||
} else if (fileName == "") {
|
||||
// sync folder itself
|
||||
// FIXME: The new parent folder logic should take over this, treating the root the same as any folder.
|
||||
} else if (type == CSYNC_FTW_TYPE_DIR) {
|
||||
if (rec.isValid()) {
|
||||
status.set(SyncFileStatus::STATUS_UPTODATE);
|
||||
} else {
|
||||
qDebug() << "Could not determine state for folder" << fileName << "will set STATUS_NEW";
|
||||
status.set(SyncFileStatus::STATUS_NEW);
|
||||
}
|
||||
} else if (type == CSYNC_FTW_TYPE_FILE) {
|
||||
if (rec.isValid()) {
|
||||
if( FileSystem::getModTime(fi.absoluteFilePath()) == Utility::qDateTimeToTime_t(rec._modtime) ) {
|
||||
status.set(SyncFileStatus::STATUS_UPTODATE);
|
||||
} else {
|
||||
if (rec._remotePerm.isNull() || rec._remotePerm.contains("W") ) {
|
||||
status.set(SyncFileStatus::STATUS_EVAL);
|
||||
} else {
|
||||
status.set(SyncFileStatus::STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Could not determine state for file" << fileName << "will set STATUS_NEW";
|
||||
status.set(SyncFileStatus::STATUS_NEW);
|
||||
}
|
||||
}
|
||||
|
||||
if (rec.isValid() && rec._remotePerm.contains("S"))
|
||||
status.setSharedWithMe(true);
|
||||
|
||||
if (status.tag() == SyncFileStatus::STATUS_NEW) {
|
||||
// check the parent folder if it is shared and if it is allowed to create a file/dir within
|
||||
QDir d( fi.path() );
|
||||
auto parentPath = d.path();
|
||||
auto dirRec = _syncEngine->journal()->getFileRecord(parentPath);
|
||||
bool isDir = type == CSYNC_FTW_TYPE_DIR;
|
||||
while( !d.isRoot() && !(d.exists() && dirRec.isValid()) ) {
|
||||
d.cdUp(); // returns true if the dir exists.
|
||||
|
||||
parentPath = d.path();
|
||||
// cut the folder path
|
||||
dirRec = _syncEngine->journal()->getFileRecord(parentPath);
|
||||
|
||||
isDir = true;
|
||||
}
|
||||
if( dirRec.isValid() && !dirRec._remotePerm.isNull()) {
|
||||
if( (isDir && !dirRec._remotePerm.contains("K"))
|
||||
|| (!isDir && !dirRec._remotePerm.contains("C")) ) {
|
||||
status.set(SyncFileStatus::STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
{
|
||||
addErroredSyncItemPathsToList(items, &_stateLastSyncItemsWithErrorNew);
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
{
|
||||
addErroredSyncItemPathsToList(items, &_stateLastSyncItemsWithErrorNew);
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotSyncFinished()
|
||||
{
|
||||
_stateLastSyncItemsWithError = _stateLastSyncItemsWithErrorNew;
|
||||
_stateLastSyncItemsWithErrorNew.clear();
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotItemCompleted(const SyncFileItem &item)
|
||||
{
|
||||
if (showErrorInSocketApi(item)) {
|
||||
_stateLastSyncItemsWithErrorNew.insert(item._file);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
51
src/libsync/syncfilestatustracker.h
Normal file
51
src/libsync/syncfilestatustracker.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SYNCFILESTATUSTRACKER_H
|
||||
#define SYNCFILESTATUSTRACKER_H
|
||||
|
||||
#include "ownsql.h"
|
||||
#include "syncfileitem.h"
|
||||
#include "syncfilestatus.h"
|
||||
#include <QSet>
|
||||
#include <csync.h>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class SyncEngine;
|
||||
|
||||
class OWNCLOUDSYNC_EXPORT SyncFileStatusTracker : public QObject
|
||||
{
|
||||
public:
|
||||
SyncFileStatusTracker(SyncEngine *syncEngine);
|
||||
SyncFileStatus fileStatus(const QString& systemFileName);
|
||||
|
||||
private slots:
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& items);
|
||||
void slotAboutToPropagate(SyncFileItemVector& items);
|
||||
void slotSyncFinished();
|
||||
void slotItemCompleted(const SyncFileItem &item);
|
||||
|
||||
private:
|
||||
bool estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s);
|
||||
|
||||
SyncEngine *_syncEngine;
|
||||
// SocketAPI: Cache files and folders that had errors so that they can
|
||||
// get a red ERROR icon.
|
||||
QSet<QString> _stateLastSyncItemsWithErrorNew; // gets moved to _stateLastSyncItemsWithError at end of sync
|
||||
QSet<QString> _stateLastSyncItemsWithError;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user