From 727e73d6401737a6b6814dab49095d7a722cc821 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Fri, 6 May 2016 12:32:01 +0200 Subject: [PATCH] [shell/windows] Fix the windows status push not working (#4784) Since the windows implementation first does cache lookups using the path string, directories need to be passed identically as through RETRIEVE_FILE_STATUS. Change the convention to never have a trailing slash for directories in the protocol. This allows the convention to be applied without having to access the disk (since we'd need to know if the path is represented by a directory) and also matches the convention of the rest of the sync engine. Individual file manager plugins are then responsible of handling pushed paths as not ending with a trailing slash. This also: - Moves the trailing slash removal logic from the SyncFileStatusTracker to the SocketApi class - Remove the unneeded QString::normalized call in fileStatus, since this should already be done by the FolderWatcher and plugins --- src/gui/socketapi.cpp | 26 ++++++++++++----- src/libsync/syncfilestatustracker.cpp | 41 ++++++++++++--------------- src/libsync/syncfilestatustracker.h | 4 +-- 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index 2e78cdb017..47ecb8509c 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -56,6 +56,13 @@ // The second number should be changed when there are new features. #define MIRALL_SOCKET_API_VERSION "1.0" +static inline QString removeTrailingSlash(QString path) +{ + Q_ASSERT(path.endsWith(QLatin1Char('/'))); + path.truncate(path.length()-1); + return path; +} + namespace OCC { #define DEBUG qDebug() << "SocketApi: " @@ -142,7 +149,7 @@ void SocketApi::slotNewConnection() foreach( Folder *f, FolderMan::instance()->map() ) { if (f->canSync()) { - QString message = buildRegisterPathMessage(f->path()); + QString message = buildRegisterPathMessage(removeTrailingSlash(f->path())); sendMessage(socket, message); } } @@ -189,7 +196,7 @@ void SocketApi::slotRegisterPath( const QString& alias ) Folder *f = FolderMan::instance()->folder(alias); if (f) { - QString message = buildRegisterPathMessage(f->path()); + QString message = buildRegisterPathMessage(removeTrailingSlash(f->path())); foreach(QIODevice *socket, _listeners) { sendMessage(socket, message); } @@ -205,7 +212,7 @@ void SocketApi::slotUnregisterPath( const QString& alias ) Folder *f = FolderMan::instance()->folder(alias); if (f) - broadcastMessage(QLatin1String("UNREGISTER_PATH"), f->path(), QString::null, true ); + broadcastMessage(QLatin1String("UNREGISTER_PATH"), removeTrailingSlash(f->path()), QString::null, true ); _registeredAliases.remove(alias); } @@ -225,10 +232,11 @@ void SocketApi::slotUpdateFolderView(Folder *f) f->syncResult().status() == SyncResult::Error || f->syncResult().status() == SyncResult::SetupError ) { - broadcastMessage(QLatin1String("STATUS"), f->path() , + QString rootPath = removeTrailingSlash(f->path()); + broadcastMessage(QLatin1String("STATUS"), rootPath, f->syncEngine().syncFileStatusTracker().fileStatus("").toSocketAPIString()); - broadcastMessage(QLatin1String("UPDATE_VIEW"), f->path() ); + broadcastMessage(QLatin1String("UPDATE_VIEW"), rootPath); } else { qDebug() << "Not sending UPDATE_VIEW for" << f->alias() << "because status() is" << f->syncResult().status(); } @@ -302,8 +310,12 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* // this can happen in offline mode e.g.: nothing to worry about statusString = QLatin1String("NOP"); } else { - const QString file = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1); - SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(file); + QString relativePath = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1); + if( relativePath.endsWith(QLatin1Char('/')) ) { + relativePath.truncate(relativePath.length()-1); + qWarning() << "Removed trailing slash for directory: " << relativePath << "Status pushes won't have one."; + } + SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(relativePath); statusString = fileStatus.toSocketAPIString(); } diff --git a/src/libsync/syncfilestatustracker.cpp b/src/libsync/syncfilestatustracker.cpp index c32e4d664e..c749ae3a34 100644 --- a/src/libsync/syncfilestatustracker.cpp +++ b/src/libsync/syncfilestatustracker.cpp @@ -92,15 +92,11 @@ SyncFileItem SyncFileStatusTracker::rootSyncFileItem() return fakeRootItem; } -SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& systemFileName) +SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& relativePath) { - QString fileName = systemFileName.normalized(QString::NormalizationForm_C); - if( fileName.endsWith(QLatin1Char('/')) ) { - fileName.truncate(fileName.length()-1); - qDebug() << "Removed trailing slash: " << fileName; - } + Q_ASSERT(!relativePath.endsWith(QLatin1Char('/'))); - if( fileName.isEmpty() ) { + if (relativePath.isEmpty()) { // This is the root sync folder, it doesn't have an entry in the database and won't be walked by csync, so create one manually. return syncFileItemStatus(rootSyncFileItem()); } @@ -111,22 +107,22 @@ SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& systemFileName) // update the exclude list at runtime and doing it statically here removes // our ability to notify changes through the fileStatusChanged signal, // it's an acceptable compromize to treat all exclude types the same. - if( _syncEngine->excludedFiles().isExcluded(_syncEngine->localPath() + fileName, + if( _syncEngine->excludedFiles().isExcluded(_syncEngine->localPath() + relativePath, _syncEngine->localPath(), _syncEngine->ignoreHiddenFiles()) ) { return SyncFileStatus(SyncFileStatus::StatusWarning); } - if ( _dirtyPaths.contains(fileName) ) + if ( _dirtyPaths.contains(relativePath) ) return SyncFileStatus::StatusSync; - SyncFileItem* item = _syncEngine->findSyncItem(fileName); + SyncFileItem* item = _syncEngine->findSyncItem(relativePath); if (item) { return syncFileItemStatus(*item); } // If we're not currently syncing that file, look it up in the database to know if it's shared - SyncJournalFileRecord rec = _syncEngine->journal()->getFileRecord(fileName); + SyncJournalFileRecord rec = _syncEngine->journal()->getFileRecord(relativePath); if (rec.isValid()) { return syncFileItemStatus(rec.toSyncFileItem()); } @@ -158,7 +154,7 @@ void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items) } else if (showWarningInSocketApi(*item)) { _syncProblems[item->_file] = SyncFileStatus::StatusWarning; } - emit fileStatusChanged(getSystemDestination(*item), syncFileItemStatus(*item)); + emit fileStatusChanged(getSystemDestination(item->destination()), syncFileItemStatus(*item)); } // Make sure to push any status that might have been resolved indirectly since the last sync @@ -170,7 +166,7 @@ void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items) SyncFileStatus::SyncFileStatusTag severity = it->second; if (severity == SyncFileStatus::StatusError) invalidateParentPaths(path); - emit fileStatusChanged(_syncEngine->localPath() + path, fileStatus(path)); + emit fileStatusChanged(getSystemDestination(path), fileStatus(path)); } } @@ -188,7 +184,7 @@ void SyncFileStatusTracker::slotItemCompleted(const SyncFileItem &item) Q_ASSERT(_syncProblems.find(item._file) == _syncProblems.end()); } - emit fileStatusChanged(getSystemDestination(item), syncFileItemStatus(item)); + emit fileStatusChanged(getSystemDestination(item.destination()), syncFileItemStatus(item)); } void SyncFileStatusTracker::slotSyncEngineRunningChanged() @@ -236,20 +232,19 @@ void SyncFileStatusTracker::invalidateParentPaths(const QString& path) QStringList splitPath = path.split('/', QString::SkipEmptyParts); for (int i = 0; i < splitPath.size(); ++i) { QString parentPath = QStringList(splitPath.mid(0, i)).join(QLatin1String("/")); - emit fileStatusChanged(_syncEngine->localPath() + parentPath, fileStatus(parentPath)); + emit fileStatusChanged(getSystemDestination(parentPath), fileStatus(parentPath)); } } -QString SyncFileStatusTracker::getSystemDestination(const SyncFileItem& item) +QString SyncFileStatusTracker::getSystemDestination(const QString& relativePath) { - QString systemFileName = _syncEngine->localPath() + item.destination(); - // the trailing slash for directories must be appended as the filenames coming in - // from the plugins have that too. Otherwise the matching entry item is not found - // in the plugin. - if( item._type == SyncFileItem::Type::Directory ) { - systemFileName += QLatin1Char('/'); + QString systemPath = _syncEngine->localPath() + relativePath; + // SyncEngine::localPath() has a trailing slash, make sure to remove it if the + // destination is empty. + if( systemPath.endsWith(QLatin1Char('/')) ) { + systemPath.truncate(systemPath.length()-1); } - return systemFileName; + return systemPath; } } diff --git a/src/libsync/syncfilestatustracker.h b/src/libsync/syncfilestatustracker.h index 4158d696d3..d141b4b178 100644 --- a/src/libsync/syncfilestatustracker.h +++ b/src/libsync/syncfilestatustracker.h @@ -35,7 +35,7 @@ class OWNCLOUDSYNC_EXPORT SyncFileStatusTracker : public QObject Q_OBJECT public: explicit SyncFileStatusTracker(SyncEngine* syncEngine); - SyncFileStatus fileStatus(const QString& systemFileName); + SyncFileStatus fileStatus(const QString& relativePath); public slots: void slotPathTouched(const QString& fileName); @@ -54,7 +54,7 @@ private: SyncFileItem rootSyncFileItem(); void invalidateParentPaths(const QString& path); - QString getSystemDestination(const SyncFileItem& syncEnginePath); + QString getSystemDestination(const QString& relativePath); SyncEngine* _syncEngine;