From 45f1a3339a881399563a6b98a60c37d39ee22e78 Mon Sep 17 00:00:00 2001 From: Dries Mys Date: Sun, 2 Jul 2023 19:05:37 +0200 Subject: [PATCH 1/3] Set VFS PinState to Excluded for ignored files. Setting PinState to Excluded ensures the syncing icon is not shown for ignored items. If the PinState is not set to Excluded, also all parent directories are shown as being synced, which is very inconvenient for the end user as it seems that some folder are never fully synced by Nextcloud which isn't the case. As long as .lnk files are not converted to placeholder files, also set them to Excluded to hide the syncing icon. Closes #5524 Closes #5594 Co-authored-by: Matthieu Gallien Signed-off-by: Dries Mys --- src/common/pinstate.h | 7 ++++++ src/gui/folder.cpp | 30 ++++++++++++++++++++++++++ src/gui/folder.h | 3 +++ src/gui/folderwatcher.cpp | 15 ++----------- src/gui/folderwatcher.h | 6 +++--- src/libsync/vfs/cfapi/cfapiwrapper.cpp | 4 ++++ src/libsync/vfs/cfapi/vfs_cfapi.cpp | 16 +++++++++++++- src/libsync/vfs/cfapi/vfs_cfapi.h | 3 +++ 8 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/common/pinstate.h b/src/common/pinstate.h index 7d4222a01ccc8..d2bc9f11ba001 100644 --- a/src/common/pinstate.h +++ b/src/common/pinstate.h @@ -75,6 +75,13 @@ enum class PinState { * dehydrated (which is an arbitrary decision). */ Unspecified = 3, + + /** The file will never be synced to the cloud. + * + * Usefull for ignored files to indicate to the OS the file will never be + * synced + */ + Excluded = 4, }; Q_ENUM_NS(PinState) diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index 31542c6bc9f6d..664054a37f2ad 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -561,6 +561,21 @@ void Folder::slotWatchedPathChanged(const QString &path, ChangeReason reason) auto relativePath = path.midRef(this->path().size()); + if (pathIsIgnored(path)) { + const auto pinState = _vfs->pinState(relativePath.toString()); + if (!pinState || *pinState != PinState::Excluded) { + if (!_vfs->setPinState(relativePath.toString(), PinState::Excluded)) + qCWarning(lcFolder) << "Could not set pin state of" << relativePath << "to excluded"; + } + return; + } else { + const auto pinState = _vfs->pinState(relativePath.toString()); + if (pinState && *pinState == PinState::Excluded) { + if (!_vfs->setPinState(relativePath.toString(), PinState::Inherited)) + qCWarning(lcFolder) << "Could not switch pin state of" << relativePath << "from" << *pinState << "to inherited"; + } + } + // Add to list of locally modified paths // // We do this before checking for our own sync-related changes to make @@ -806,6 +821,21 @@ void Folder::removeFromSettings() const settings->remove(FolderMan::escapeAlias(_definition.alias)); } +bool Folder::pathIsIgnored(const QString &path) const +{ + if (path.isEmpty()) { + return true; + } + +#ifndef OWNCLOUD_TEST + if (isFileExcludedAbsolute(path) && !Utility::isConflictFile(path)) { + qCDebug(lcFolder) << "* Ignoring file" << path; + return true; + } +#endif + return false; +} + bool Folder::isFileExcludedAbsolute(const QString &fullPath) const { return _engine->excludedFiles().isExcluded(fullPath, path(), _definition.ignoreHiddenFiles); diff --git a/src/gui/folder.h b/src/gui/folder.h index 9d654baed9258..cac47809ba112 100644 --- a/src/gui/folder.h +++ b/src/gui/folder.h @@ -233,6 +233,9 @@ class Folder : public QObject /// Removes the folder from the account's settings. void removeFromSettings() const; + /* Check if the path is ignored. */ + [[nodiscard]] bool pathIsIgnored(const QString &path) const; + /** * Returns whether a file inside this folder should be excluded. */ diff --git a/src/gui/folderwatcher.cpp b/src/gui/folderwatcher.cpp index 3d1f73cba3d47..b050af74cfc00 100644 --- a/src/gui/folderwatcher.cpp +++ b/src/gui/folderwatcher.cpp @@ -66,20 +66,9 @@ void FolderWatcher::init(const QString &root) _timer.start(); } -bool FolderWatcher::pathIsIgnored(const QString &path) +bool FolderWatcher::pathIsIgnored(const QString &path) const { - if (path.isEmpty()) - return true; - if (!_folder) - return false; - -#ifndef OWNCLOUD_TEST - if (_folder->isFileExcludedAbsolute(path) && !Utility::isConflictFile(path)) { - qCDebug(lcFolderWatcher) << "* Ignoring file" << path; - return true; - } -#endif - return false; + return path.isEmpty(); } bool FolderWatcher::isReliable() const diff --git a/src/gui/folderwatcher.h b/src/gui/folderwatcher.h index 3403fabbda032..0e7b50cee641f 100644 --- a/src/gui/folderwatcher.h +++ b/src/gui/folderwatcher.h @@ -60,9 +60,6 @@ class FolderWatcher : public QObject */ void init(const QString &root); - /* Check if the path is ignored. */ - bool pathIsIgnored(const QString &path); - /** * Returns false if the folder watcher can't be trusted to capture all * notifications. @@ -135,6 +132,9 @@ private slots: QString possiblyAddUnlockedFilePath(const QString &path); QString findMatchingUnlockedFileInDir(const QString &dirPath, const QString &lockFileName); + /* Check if the path should be igored by the FolderWatcher. */ + [[nodiscard]] bool pathIsIgnored(const QString &path) const; + /** Path of the expected test notification */ QString _testNotificationPath; diff --git a/src/libsync/vfs/cfapi/cfapiwrapper.cpp b/src/libsync/vfs/cfapi/cfapiwrapper.cpp index 8045c61487a0d..1849deb74bed2 100644 --- a/src/libsync/vfs/cfapi/cfapiwrapper.cpp +++ b/src/libsync/vfs/cfapi/cfapiwrapper.cpp @@ -292,6 +292,8 @@ OCC::PinState cfPinStateToPinState(CF_PIN_STATE state) return OCC::PinState::OnlineOnly; case CF_PIN_STATE_INHERIT: return OCC::PinState::Inherited; + case CF_PIN_STATE_EXCLUDED: + return OCC::PinState::Excluded; default: Q_UNREACHABLE(); return OCC::PinState::Inherited; @@ -309,6 +311,8 @@ CF_PIN_STATE pinStateToCfPinState(OCC::PinState state) return CF_PIN_STATE_UNPINNED; case OCC::PinState::Unspecified: return CF_PIN_STATE_UNSPECIFIED; + case OCC::PinState::Excluded: + return CF_PIN_STATE_EXCLUDED; default: Q_UNREACHABLE(); return CF_PIN_STATE_UNSPECIFIED; diff --git a/src/libsync/vfs/cfapi/vfs_cfapi.cpp b/src/libsync/vfs/cfapi/vfs_cfapi.cpp index a259ef9222be9..9c32cc82937b1 100644 --- a/src/libsync/vfs/cfapi/vfs_cfapi.cpp +++ b/src/libsync/vfs/cfapi/vfs_cfapi.cpp @@ -224,12 +224,16 @@ Result VfsCfApi::dehydratePlaceholder(const SyncFileItem &item) Result VfsCfApi::convertToPlaceholder(const QString &filename, const SyncFileItem &item, const QString &replacesFile) { + const auto localPath = QDir::toNativeSeparators(filename); + if (item._type != ItemTypeDirectory && OCC::FileSystem::isLnkFile(filename)) { qCInfo(lcCfApi) << "File \"" << filename << "\" is a Windows shortcut. Not converting it to a placeholder."; + const auto pinState = pinStateLocal(localPath); + if (!pinState || *pinState != PinState::Excluded) + setPinStateLocal(localPath, PinState::Excluded); return Vfs::ConvertToPlaceholderResult::Ok; } - const auto localPath = QDir::toNativeSeparators(filename); const auto replacesPath = QDir::toNativeSeparators(replacesFile); if (cfapi::findPlaceholderInfo(localPath)) { @@ -293,6 +297,11 @@ bool VfsCfApi::setPinState(const QString &folderPath, PinState state) const auto localPath = QDir::toNativeSeparators(params().filesystemPath + folderPath); + return setPinStateLocal(localPath, state); +} + +bool VfsCfApi::setPinStateLocal(const QString &localPath, PinState state) +{ if (cfapi::setPinState(localPath, state, cfapi::Recurse)) { return true; } else { @@ -304,6 +313,11 @@ Optional VfsCfApi::pinState(const QString &folderPath) { const auto localPath = QDir::toNativeSeparators(params().filesystemPath + folderPath); + return pinStateLocal(localPath); +} + +Optional VfsCfApi::pinStateLocal(const QString &localPath) const +{ const auto info = cfapi::findPlaceholderInfo(localPath); if (!info) { qCWarning(lcCfApi) << "Couldn't find pin state for regular non-placeholder file" << localPath; diff --git a/src/libsync/vfs/cfapi/vfs_cfapi.h b/src/libsync/vfs/cfapi/vfs_cfapi.h index 3803bf1485221..b675ae389f0e7 100644 --- a/src/libsync/vfs/cfapi/vfs_cfapi.h +++ b/src/libsync/vfs/cfapi/vfs_cfapi.h @@ -76,6 +76,9 @@ public slots: void onHydrationJobFinished(HydrationJob *job); HydrationJob *findHydrationJob(const QString &requestId) const; + bool setPinStateLocal(const QString &localPath, PinState state); + [[nodiscard]] Optional pinStateLocal(const QString &localPath) const; + struct HasHydratedDehydrated { bool hasHydrated = false; bool hasDehydrated = false; From 6ac29eea2c1c80c2954529189de375640775162c Mon Sep 17 00:00:00 2001 From: Dries Mys Date: Tue, 18 Jul 2023 22:49:16 +0200 Subject: [PATCH 2/3] Remove warning when querying pin state on non-placeholder file F.ex. Folder::slotWatchedPathChanged calls this function on non- placeholder files to check if the ignored file is already assigned an Excluded pin state. Note that it is allowed to set the pin state to Excluded on non-placeholder files. Signed-off-by: Dries Mys --- src/libsync/vfs/cfapi/vfs_cfapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsync/vfs/cfapi/vfs_cfapi.cpp b/src/libsync/vfs/cfapi/vfs_cfapi.cpp index 9c32cc82937b1..1c5c3e91c6c51 100644 --- a/src/libsync/vfs/cfapi/vfs_cfapi.cpp +++ b/src/libsync/vfs/cfapi/vfs_cfapi.cpp @@ -320,7 +320,7 @@ Optional VfsCfApi::pinStateLocal(const QString &localPath) const { const auto info = cfapi::findPlaceholderInfo(localPath); if (!info) { - qCWarning(lcCfApi) << "Couldn't find pin state for regular non-placeholder file" << localPath; + qCDebug(lcCfApi) << "Couldn't find pin state for regular non-placeholder file" << localPath; return {}; } From 470a983b474d9f00fa1c880f97c57c38acbc08e0 Mon Sep 17 00:00:00 2001 From: Dries Mys Date: Wed, 19 Jul 2023 10:55:36 +0200 Subject: [PATCH 3/3] Small coding improvements Signed-off-by: Dries Mys --- src/gui/folder.cpp | 6 ++++-- src/libsync/vfs/cfapi/vfs_cfapi.cpp | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index 664054a37f2ad..e9f05e79f2989 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -564,15 +564,17 @@ void Folder::slotWatchedPathChanged(const QString &path, ChangeReason reason) if (pathIsIgnored(path)) { const auto pinState = _vfs->pinState(relativePath.toString()); if (!pinState || *pinState != PinState::Excluded) { - if (!_vfs->setPinState(relativePath.toString(), PinState::Excluded)) + if (!_vfs->setPinState(relativePath.toString(), PinState::Excluded)) { qCWarning(lcFolder) << "Could not set pin state of" << relativePath << "to excluded"; + } } return; } else { const auto pinState = _vfs->pinState(relativePath.toString()); if (pinState && *pinState == PinState::Excluded) { - if (!_vfs->setPinState(relativePath.toString(), PinState::Inherited)) + if (!_vfs->setPinState(relativePath.toString(), PinState::Inherited)) { qCWarning(lcFolder) << "Could not switch pin state of" << relativePath << "from" << *pinState << "to inherited"; + } } } diff --git a/src/libsync/vfs/cfapi/vfs_cfapi.cpp b/src/libsync/vfs/cfapi/vfs_cfapi.cpp index 1c5c3e91c6c51..931da6f1938e6 100644 --- a/src/libsync/vfs/cfapi/vfs_cfapi.cpp +++ b/src/libsync/vfs/cfapi/vfs_cfapi.cpp @@ -229,8 +229,9 @@ Result VfsCfApi::convertToPlaceholder( if (item._type != ItemTypeDirectory && OCC::FileSystem::isLnkFile(filename)) { qCInfo(lcCfApi) << "File \"" << filename << "\" is a Windows shortcut. Not converting it to a placeholder."; const auto pinState = pinStateLocal(localPath); - if (!pinState || *pinState != PinState::Excluded) + if (!pinState || *pinState != PinState::Excluded) { setPinStateLocal(localPath, PinState::Excluded); + } return Vfs::ConvertToPlaceholderResult::Ok; }