Update Word files VFS placeholders each time they get opened by tracking the 'lock...
authoralex-z <blackslayer4@gmail.com>
Mon, 28 Aug 2023 15:07:27 +0000 (17:07 +0200)
committerMatthieu Gallien <matthieu_gallien@yahoo.fr>
Fri, 1 Sep 2023 13:04:17 +0000 (15:04 +0200)
Signed-off-by: alex-z <blackslayer4@gmail.com>
src/gui/folder.cpp
src/gui/folder.h
src/gui/folderwatcher.cpp
src/gui/folderwatcher.h

index a0889f5c3dae1ad8d598683bfe66c18812d84ac2..2aa8ee48e673e9cbf95645996b8eb3379b80a323 100644 (file)
@@ -641,8 +641,11 @@ void Folder::slotFilesLockReleased(const QSet<QString> &files)
     for (const auto &file : files) {
         const auto fileRecordPath = fileFromLocalPath(file);
         SyncJournalFileRecord rec;
-        const auto canUnlockFile = journalDb()->getFileRecord(fileRecordPath, &rec)
-            && rec.isValid()
+        const auto isFileRecordValid = journalDb()->getFileRecord(fileRecordPath, &rec) && rec.isValid();
+        if (isFileRecordValid) {
+            [[maybe_unused]] const auto result = _vfs->updateMetadata(path() + rec.path(), rec._modtime, rec._fileSize, rec._fileId);
+        }
+        const auto canUnlockFile = isFileRecordValid
             && rec._lockstate._locked
             && rec._lockstate._lockOwnerType == static_cast<qint64>(SyncFileItem::LockOwnerType::UserLock)
             && rec._lockstate._lockOwnerId == _accountState->account()->davUser();
@@ -667,6 +670,18 @@ void Folder::slotFilesLockReleased(const QSet<QString> &files)
     }
 }
 
+void Folder::slotFilesLockImposed(const QSet<QString> &files)
+{
+    qCDebug(lcFolder) << "Lock files detected for office files" << files;
+    for (const auto &file : files) {
+        const auto fileRecordPath = fileFromLocalPath(file);
+        SyncJournalFileRecord rec;
+        if (journalDb()->getFileRecord(fileRecordPath, &rec) && rec.isValid()) {
+            [[maybe_unused]] const auto result = _vfs->updateMetadata(path() + rec.path(), rec._modtime, rec._fileSize, rec._fileId);
+        }
+    }
+}
+
 void Folder::implicitlyHydrateFile(const QString &relativepath)
 {
     qCInfo(lcFolder) << "Implicitly hydrate virtual file:" << relativepath;
@@ -1498,6 +1513,7 @@ void Folder::registerFolderWatcher()
     if (_accountState->account()->capabilities().filesLockAvailable()) {
         connect(_folderWatcher.data(), &FolderWatcher::filesLockReleased, this, &Folder::slotFilesLockReleased);
     }
+    connect(_folderWatcher.data(), &FolderWatcher::filesLockImposed, this, &Folder::slotFilesLockImposed, Qt::UniqueConnection);
     _folderWatcher->init(path());
     _folderWatcher->startNotificatonTest(path() + QLatin1String(".nextcloudsync.log"));
 }
index 13f493102ee91772676dcb7bb3d0c294232762da..f0459a9f03ba7f7fd8381838a380a04337087c70 100644 (file)
@@ -353,6 +353,11 @@ public slots:
     */
     void slotFilesLockReleased(const QSet<QString> &files);
 
+    /*
+     * Triggered when lock files were added
+     */
+    void slotFilesLockImposed(const QSet<QString> &files);
+
     /**
      * Mark a virtual file as being requested for download, and start a sync.
      *
index b050af74cfc000440fe7dd855ee14070a69e11d7..44b56d391ca5b4ba22e0a027e873c63b2cb17367 100644 (file)
@@ -170,6 +170,7 @@ void FolderWatcher::changeDetected(const QStringList &paths)
 
     QSet<QString> changedPaths;
     QSet<QString> unlockedFiles;
+    QSet<QString> lockedFiles;
 
     for (int i = 0; i < paths.size(); ++i) {
         QString path = paths[i];
@@ -178,15 +179,21 @@ void FolderWatcher::changeDetected(const QStringList &paths)
             _testNotificationPath.clear();
         }
         
+        const auto checkResult = checkIfFileIsLockOrUnlock(path);
         if (_shouldWatchForFileUnlocking) {
-            const auto unlockedFilePath = possiblyAddUnlockedFilePath(path);
-            if (!unlockedFilePath.isEmpty()) {
-                unlockedFiles.insert(unlockedFilePath);
+            if (checkResult.type == FileLockingInfo::Type::Unlocked && !checkResult.path.isEmpty()) {
+                unlockedFiles.insert(checkResult.path);
             }
 
             qCDebug(lcFolderWatcher) << "Unlocked files:" << unlockedFiles.values();
         }
 
+        if (checkResult.type == FileLockingInfo::Type::Locked && !checkResult.path.isEmpty()) {
+            lockedFiles.insert(checkResult.path);
+        }
+
+        qCDebug(lcFolderWatcher) << "Locked files:" << lockedFiles.values();
+
     // ------- handle ignores:
         if (pathIsIgnored(path)) {
             continue;
@@ -199,6 +206,10 @@ void FolderWatcher::changeDetected(const QStringList &paths)
         emit filesLockReleased(unlockedFiles);
     }
 
+    if (!lockedFiles.isEmpty()) {
+        emit filesLockImposed(lockedFiles);
+    }
+
     if (changedPaths.isEmpty()) {
         return;
     }
@@ -214,12 +225,14 @@ void FolderWatcher::folderAccountCapabilitiesChanged()
     _shouldWatchForFileUnlocking = _folder->accountState()->account()->capabilities().filesLockAvailable();
 }
 
-QString FolderWatcher::possiblyAddUnlockedFilePath(const QString &path)
+FolderWatcher::FileLockingInfo FolderWatcher::checkIfFileIsLockOrUnlock(const QString &path) const
 {
     qCDebug(lcFolderWatcher) << "Checking if it is a lock file:" << path;
+
+    FileLockingInfo result;
     const auto pathSplit = path.split(QLatin1Char('/'), Qt::SkipEmptyParts);
     if (pathSplit.isEmpty()) {
-        return {};
+        return result;
     }
     QString lockFilePatternFound;
     for (const auto &lockFilePattern : lockFilePatterns) {
@@ -229,8 +242,8 @@ QString FolderWatcher::possiblyAddUnlockedFilePath(const QString &path)
         }
     }
 
-    if (lockFilePatternFound.isEmpty() || QFileInfo::exists(path)) {
-        return {};
+    if (lockFilePatternFound.isEmpty()) {
+        return result;
     }
 
     qCDebug(lcFolderWatcher) << "Found a lock file with prefix:" << lockFilePatternFound << "in path:" << path;
@@ -239,7 +252,7 @@ QString FolderWatcher::possiblyAddUnlockedFilePath(const QString &path)
     auto lockFilePathWithoutPrefixSplit = lockFilePathWitoutPrefix.split(QLatin1Char('.'));
 
     if (lockFilePathWithoutPrefixSplit.size() < 2) {
-        return {};
+        return result;
     }
 
     auto extensionSanitized = lockFilePathWithoutPrefixSplit.takeLast().toStdString();
@@ -252,26 +265,26 @@ QString FolderWatcher::possiblyAddUnlockedFilePath(const QString &path)
     );
 
     lockFilePathWithoutPrefixSplit.push_back(QString::fromStdString(extensionSanitized));
-    auto unlockedFilePath = lockFilePathWithoutPrefixSplit.join(QLatin1Char('.'));
-
-    if (!QFile::exists(unlockedFilePath)) {
-        unlockedFilePath.clear();
-        qCDebug(lcFolderWatcher) << "Assumed unlocked file path" << unlockedFilePath << "does not exist. Going to try to find matching file";
-        auto splitFilePath = unlockedFilePath.split(QLatin1Char('/'));
-        if (splitFilePath.size() > 1) {
-            const auto lockFileName = splitFilePath.takeLast();
-            // some software will modify lock file name such that it does not correspond to original file (removing some symbols from the name, so we will search for a matching file
-            unlockedFilePath = findMatchingUnlockedFileInDir(splitFilePath.join(QLatin1Char('/')), lockFileName);
-        }
+    const auto lockFilePathWithoutPrefix = lockFilePathWithoutPrefixSplit.join(QLatin1Char('.'));
+
+    qCDebug(lcFolderWatcher) << "Assumed locked/unlocked file path" << lockFilePathWithoutPrefix << "Going to try to find matching file";
+    auto splitFilePath = lockFilePathWithoutPrefix.split(QLatin1Char('/'));
+    if (splitFilePath.size() > 1) {
+        const auto lockFileNameWithoutPrefix = splitFilePath.takeLast();
+        // some software will modify lock file name such that it does not correspond to original file (removing some symbols from the name, so we will search
+        // for a matching file
+        result.path = findMatchingUnlockedFileInDir(splitFilePath.join(QLatin1Char('/')), lockFileNameWithoutPrefix);
     }
 
-    if (unlockedFilePath.isEmpty() || !QFile::exists(unlockedFilePath)) {
-        return {};
+    if (result.path.isEmpty() || !QFile::exists(result.path)) {
+        result.path.clear();
+        return result;
     }
-    return unlockedFilePath;
+    result.type = QFile::exists(path) ? FileLockingInfo::Type::Locked : FileLockingInfo::Type::Unlocked;
+    return result;
 }
 
-QString FolderWatcher::findMatchingUnlockedFileInDir(const QString &dirPath, const QString &lockFileName)
+QString FolderWatcher::findMatchingUnlockedFileInDir(const QString &dirPath, const QString &lockFileName) const
 {
     QString foundFilePath;
     const QDir dir(dirPath);
index 0e7b50cee641f08fd9ebf8d1109c570989cc0cb3..f2d59f703d6dd074c5b0e0f0b3669253da662b3e 100644 (file)
@@ -50,6 +50,13 @@ class Folder;
 class FolderWatcher : public QObject
 {
     Q_OBJECT
+
+    struct FileLockingInfo {
+        enum class Type { Unset = -1, Locked, Unlocked };
+        QString path;
+        Type type = Type::Unset;
+    };
+
 public:
     // Construct, connect signals, call init()
     explicit FolderWatcher(Folder *folder = nullptr);
@@ -90,6 +97,11 @@ signals:
     */
     void filesLockReleased(const QSet<QString> &files);
 
+    /*
+     * Emitted when lock files were added
+     */
+    void filesLockImposed(const QSet<QString> &files);
+
     /**
      * Emitted if some notifications were lost.
      *
@@ -129,8 +141,8 @@ private:
 
     void appendSubPaths(QDir dir, QStringList& subPaths);
 
-    QString possiblyAddUnlockedFilePath(const QString &path);
-    QString findMatchingUnlockedFileInDir(const QString &dirPath, const QString &lockFileName);
+    [[nodiscard]] FileLockingInfo checkIfFileIsLockOrUnlock(const QString &path) const;
+    [[nodiscard]] QString findMatchingUnlockedFileInDir(const QString &dirPath, const QString &lockFileName) const;
 
     /* Check if the path should be igored by the FolderWatcher. */
     [[nodiscard]] bool pathIsIgnored(const QString &path) const;