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;