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();
}
}
+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;
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"));
}
QSet<QString> changedPaths;
QSet<QString> unlockedFiles;
+ QSet<QString> lockedFiles;
for (int i = 0; i < paths.size(); ++i) {
QString path = paths[i];
_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;
emit filesLockReleased(unlockedFiles);
}
+ if (!lockedFiles.isEmpty()) {
+ emit filesLockImposed(lockedFiles);
+ }
+
if (changedPaths.isEmpty()) {
return;
}
_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) {
}
}
- if (lockFilePatternFound.isEmpty() || QFileInfo::exists(path)) {
- return {};
+ if (lockFilePatternFound.isEmpty()) {
+ return result;
}
qCDebug(lcFolderWatcher) << "Found a lock file with prefix:" << lockFilePatternFound << "in path:" << path;
auto lockFilePathWithoutPrefixSplit = lockFilePathWitoutPrefix.split(QLatin1Char('.'));
if (lockFilePathWithoutPrefixSplit.size() < 2) {
- return {};
+ return result;
}
auto extensionSanitized = lockFilePathWithoutPrefixSplit.takeLast().toStdString();
);
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);
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);
*/
void filesLockReleased(const QSet<QString> &files);
+ /*
+ * Emitted when lock files were added
+ */
+ void filesLockImposed(const QSet<QString> &files);
+
/**
* Emitted if some notifications were lost.
*
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;