bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString &path, RemotePermissions remotePerm) { if (_syncOptions._confirmExternalStorage && !_syncOptions._newFilesAreVirtual && remotePerm.hasPermission(RemotePermissions::IsMounted)) { // external storage. /* Note: DiscoverySingleDirectoryJob::directoryListingIteratedSlot make sure that only the * root of a mounted storage has 'M', all sub entries have 'm' */ // Only allow it if the white list contains exactly this path (not parents) // We want to ask confirmation for external storage even if the parents where selected if (_selectiveSyncWhiteList.contains(path + QLatin1Char('/'))) { return false; } emit newBigFolder(path, true); return true; } // If this path or the parent is in the white list, then we do not block this file if (findPathInList(_selectiveSyncWhiteList, path)) { return false; } auto limit = _syncOptions._newBigFolderSizeLimit; if (limit < 0 || _syncOptions._newFilesAreVirtual) { // no limit, everything is allowed; return false; } // Go in the main thread to do a PROPFIND to know the size of this folder qint64 result = -1; { QMutexLocker locker(&_vioMutex); emit doGetSizeSignal(path, &result); _vioWaitCondition.wait(&_vioMutex); } if (result >= limit) { // we tell the UI there is a new folder emit newBigFolder(path, false); return true; } else { // it is not too big, put it in the white list (so we will not do more query for the children) // and and do not block. auto p = path; if (!p.endsWith(QLatin1Char('/'))) { p += QLatin1Char('/'); } _selectiveSyncWhiteList.insert(std::upper_bound(_selectiveSyncWhiteList.begin(), _selectiveSyncWhiteList.end(), p), p); return false; } }
void SyncEngine::startSync() { if (_journal->exists()) { QVector< SyncJournalDb::PollInfo > pollInfos = _journal->getPollInfos(); if (!pollInfos.isEmpty()) { qDebug() << "Finish Poll jobs before starting a sync"; CleanupPollsJob *job = new CleanupPollsJob(pollInfos, _account, _journal, _localPath, this); connect(job, SIGNAL(finished()), this, SLOT(startSync())); connect(job, SIGNAL(aborted(QString)), this, SLOT(slotCleanPollsJobAborted(QString))); job->start(); return; } } Q_ASSERT(!_syncRunning); _syncRunning = true; Q_ASSERT(_csync_ctx); if (!QDir(_localPath).exists()) { // No _tr, it should only occur in non-mirall emit csyncError("Unable to find local sync folder."); finalize(false); return; } // Check free size on disk first. const qint64 minFree = criticalFreeSpaceLimit(); const qint64 freeBytes = Utility::freeDiskSpace(_localPath); if (freeBytes >= 0) { qDebug() << "There are" << freeBytes << "bytes available at" << _localPath << "and at least" << minFree << "are required"; if (freeBytes < minFree) { emit csyncError(tr("Only %1 are available, need at least %2 to start").arg( Utility::octetsToString(freeBytes), Utility::octetsToString(minFree))); finalize(false); return; } } else { qDebug() << "Could not determine free space available at" << _localPath; } _syncedItems.clear(); _syncItemMap.clear(); _needsUpdate = false; csync_resume(_csync_ctx); int fileRecordCount = -1; if (!_journal->exists()) { qDebug() << "=====sync looks new (no DB exists)"; } else { qDebug() << "=====sync with existing DB"; } qDebug() << "=====Using Qt" << qVersion(); #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) qDebug() << "=====Using SSL library version" << QSslSocket::sslLibraryVersionString().toUtf8().data(); #endif fileRecordCount = _journal->getFileRecordCount(); // this creates the DB if it does not exist yet if( fileRecordCount == -1 ) { qDebug() << "No way to create a sync journal!"; emit csyncError(tr("Unable to initialize a sync journal.")); finalize(false); return; // database creation error! } _csync_ctx->read_remote_from_db = true; // This tells csync to never read from the DB if it is empty // thereby speeding up the initial discovery significantly. _csync_ctx->db_is_empty = (fileRecordCount == 0); auto selectiveSyncBlackList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList); bool usingSelectiveSync = (!selectiveSyncBlackList.isEmpty()); qDebug() << (usingSelectiveSync ? "====Using Selective Sync" : "====NOT Using Selective Sync"); csync_set_userdata(_csync_ctx, this); _stopWatch.start(); qDebug() << "#### Discovery start #################################################### >>"; _discoveryMainThread = new DiscoveryMainThread(account()); _discoveryMainThread->setParent(this); connect(this, SIGNAL(finished(bool)), _discoveryMainThread, SLOT(deleteLater())); qDebug() << "=====Server" << account()->serverVersion() << QString("rootEtagChangesNotOnlySubFolderEtags=%1").arg(account()->rootEtagChangesNotOnlySubFolderEtags()); if (account()->rootEtagChangesNotOnlySubFolderEtags()) { connect(_discoveryMainThread, SIGNAL(etag(QString)), this, SLOT(slotRootEtagReceived(QString))); } else { connect(_discoveryMainThread, SIGNAL(etagConcatenation(QString)), this, SLOT(slotRootEtagReceived(QString))); } DiscoveryJob *discoveryJob = new DiscoveryJob(_csync_ctx); discoveryJob->_selectiveSyncBlackList = selectiveSyncBlackList; discoveryJob->_selectiveSyncWhiteList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList); discoveryJob->_newBigFolderSizeLimit = _newBigFolderSizeLimit; discoveryJob->moveToThread(&_thread); connect(discoveryJob, SIGNAL(finished(int)), this, SLOT(slotDiscoveryJobFinished(int))); connect(discoveryJob, SIGNAL(folderDiscovered(bool,QString)), this, SIGNAL(folderDiscovered(bool,QString))); connect(discoveryJob, SIGNAL(newBigFolder(QString)), this, SIGNAL(newBigFolder(QString))); // This is used for the DiscoveryJob to be able to request the main thread/ // to read in directory contents. qDebug() << Q_FUNC_INFO << _remotePath << _remoteUrl; _discoveryMainThread->setupHooks( discoveryJob, _remotePath); // Starts the update in a seperate thread QMetaObject::invokeMethod(discoveryJob, "start", Qt::QueuedConnection); }
void Folder::startSync(const QStringList &pathList) { Q_ASSERT(_accountState); Q_UNUSED(pathList) if (!_csync_ctx) { // no _csync_ctx yet, initialize it. init(); if (!_csync_ctx) { qDebug() << Q_FUNC_INFO << "init failed."; // the error should already be set QMetaObject::invokeMethod(this, "slotSyncFinished", Qt::QueuedConnection); return; } } else if (proxyDirty()) { setProxyDirty(false); } csync_set_log_level( Logger::instance()->isNoop() ? 0 : 11 ); if (isBusy()) { qCritical() << "* ERROR csync is still running and new sync requested."; return; } _errors.clear(); _csyncError = false; _csyncUnavail = false; _timeSinceLastSyncStart.restart(); _syncResult.clearErrors(); _syncResult.setStatus( SyncResult::SyncPrepare ); _syncResult.setSyncFileItemVector(SyncFileItemVector()); emit syncStateChange(); qDebug() << "*** Start syncing " << alias() << " - client version" << qPrintable(Theme::instance()->version()); if (! setIgnoredFiles()) { slotSyncError(tr("Could not read system exclude file")); QMetaObject::invokeMethod(this, "slotSyncFinished", Qt::QueuedConnection); return; } // pass the setting if hidden files are to be ignored, will be read in csync_update _csync_ctx->ignore_hidden_files = _definition.ignoreHiddenFiles; _engine.reset(new SyncEngine( _accountState->account(), _csync_ctx, path(), remoteUrl().path(), remotePath(), &_journal)); qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector"); qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction"); 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); connect(_engine.data(), SIGNAL(csyncError(QString)), SLOT(slotSyncError(QString)), Qt::QueuedConnection); connect(_engine.data(), SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection); //direct connection so the message box is blocking the sync. connect(_engine.data(), SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*))); connect(_engine.data(), SIGNAL(folderDiscovered(bool,QString)), this, SLOT(slotFolderDiscovered(bool,QString))); connect(_engine.data(), SIGNAL(transmissionProgress(ProgressInfo)), this, SLOT(slotTransmissionProgress(ProgressInfo))); connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)), this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &))); connect(_engine.data(), SIGNAL(syncItemDiscovered(const SyncFileItem &)), this, SLOT(slotSyncItemDiscovered(const SyncFileItem &))); connect(_engine.data(), SIGNAL(newBigFolder(QString)), this, SLOT(slotNewBigFolderDiscovered(QString))); setDirtyNetworkLimits(); ConfigFile cfgFile; auto newFolderLimit = cfgFile.newBigFolderSizeLimit(); quint64 limit = newFolderLimit.first ? newFolderLimit.second * 1000 * 1000 : -1; // convert from MB to B _engine->setNewBigFolderSizeLimit(limit); QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection); // disable events until syncing is done // _watcher->setEventsEnabled(false); emit syncStarted(); }