Fix files not unlocking after lock time expired

Signed-off-by: Claudio Cambra <claudio.cambra@gmail.com>
This commit is contained in:
Claudio Cambra 2022-09-20 23:03:39 +02:00 committed by Matthieu Gallien
parent 311469a0e5
commit fd332a52e2
5 changed files with 49 additions and 11 deletions

View file

@ -1351,7 +1351,7 @@ bool SyncJournalDb::updateFileRecordChecksum(const QString &filename,
}
bool SyncJournalDb::updateLocalMetadata(const QString &filename,
qint64 modtime, qint64 size, quint64 inode)
qint64 modtime, qint64 size, quint64 inode, const SyncJournalFileLockInfo &lockInfo)
{
QMutexLocker locker(&_mutex);
@ -1365,7 +1365,9 @@ bool SyncJournalDb::updateLocalMetadata(const QString &filename,
}
const auto query = _queryManager.get(PreparedSqlQueryManager::SetFileRecordLocalMetadataQuery, QByteArrayLiteral("UPDATE metadata"
" SET inode=?2, modtime=?3, filesize=?4"
" SET inode=?2, modtime=?3, filesize=?4, lock=?5, lockType=?6,"
" lockOwnerDisplayName=?7, lockOwnerId=?8, lockOwnerEditor = ?9,"
" lockTime=?10, lockTimeout=?11"
" WHERE phash == ?1;"),
_db);
if (!query) {
@ -1376,6 +1378,13 @@ bool SyncJournalDb::updateLocalMetadata(const QString &filename,
query->bindValue(2, inode);
query->bindValue(3, modtime);
query->bindValue(4, size);
query->bindValue(5, lockInfo._locked ? 1 : 0);
query->bindValue(6, lockInfo._lockOwnerDisplayName);
query->bindValue(7, lockInfo._lockOwnerId);
query->bindValue(8, lockInfo._lockOwnerType);
query->bindValue(9, lockInfo._lockEditorApp);
query->bindValue(10, lockInfo._lockTime);
query->bindValue(11, lockInfo._lockTimeout);
return query->exec();
}

View file

@ -78,7 +78,7 @@ public:
const QByteArray &contentChecksum,
const QByteArray &contentChecksumType);
[[nodiscard]] bool updateLocalMetadata(const QString &filename,
qint64 modtime, qint64 size, quint64 inode);
qint64 modtime, qint64 size, quint64 inode, const SyncJournalFileLockInfo &lockInfo);
/// Return value for hasHydratedOrDehydratedFiles()
struct HasHydratedDehydrated

View file

@ -394,6 +394,17 @@ void ProcessDirectoryJob::processFile(PathTuple path,
if (item->_type == ItemTypeVirtualFileDehydration)
item->_type = ItemTypeFile;
// We want to check the lock state of this file after the lock time has expired
if(serverEntry.locked == SyncFileItem::LockStatus::LockedItem) {
const auto lockExpirationTime = serverEntry.lockTime + serverEntry.lockTimeout;
const auto timeRemaining = QDateTime::currentDateTime().secsTo(QDateTime::fromSecsSinceEpoch(lockExpirationTime));
const auto timerInterval = qMax(5LL, timeRemaining);
qCInfo(lcDisco) << "Will re-check lock status for:" << path._original << "in:" << timerInterval << "seconds.";
_discoveryData->_anotherSyncNeeded = true;
_discoveryData->_scheduleSyncInSecs = timerInterval;
}
// VFS suffixed files on the server are ignored
if (isVfsWithSuffix()) {
if (hasVirtualFileSuffix(serverEntry.name)
@ -505,6 +516,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
const bool isVirtualE2EePlaceholder = isDbEntryAnE2EePlaceholder && serverEntry.size >= Constants::e2EeTagSize;
const qint64 sizeOnServer = isVirtualE2EePlaceholder ? serverEntry.size - Constants::e2EeTagSize : serverEntry.size;
const bool metaDataSizeNeedsUpdateForE2EeFilePlaceholder = isVirtualE2EePlaceholder && dbEntry._fileSize == serverEntry.size;
const bool serverEntryLockedAsBool = serverEntry.locked == SyncFileItem::LockStatus::LockedItem;
if (serverEntry.isDirectory != dbEntry.isDirectory()) {
// If the type of the entity changed, it's like NEW, but
@ -551,6 +563,8 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
}
item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
item->_direction = SyncFileItem::Down;
} else if(serverEntryLockedAsBool != dbEntry._lockstate._locked) {
item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
} else {
// if (is virtual mode enabled and folder is encrypted - check if the size is the same as on the server and then - trigger server query
// to update a placeholder with corrected size (-16 Bytes)
@ -815,7 +829,7 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
bool serverModified = item->_instruction == CSYNC_INSTRUCTION_NEW || item->_instruction == CSYNC_INSTRUCTION_SYNC
|| item->_instruction == CSYNC_INSTRUCTION_RENAME || item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE;
qCDebug(lcDisco) << "File" << item->_file << "- servermodified:" << serverModified
<< "noServerEntry:" << noServerEntry;
@ -1029,7 +1043,7 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
item->_size = localEntry.size;
item->_modtime = localEntry.modtime;
_childModified = true;
qCDebug(lcDisco) << "Local file was changed: File" << item->_file
<< "item->_instruction:" << item->_instruction
<< "noServerEntry:" << noServerEntry
@ -1316,7 +1330,7 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
chopVirtualFileSuffix(serverOriginalPath);
auto job = new RequestEtagJob(_discoveryData->_account, serverOriginalPath, this);
connect(job, &RequestEtagJob::finishedWithResult, this, [=](const HttpResult<QByteArray> &etag) mutable {
if (!etag || (etag.get() != base._etag && !item->isDirectory()) || _discoveryData->isRenamed(originalPath)
|| (isAnyParentBeingRestored(originalPath) && !isRename(originalPath))) {
@ -1382,7 +1396,7 @@ void ProcessDirectoryJob::processFileConflict(const SyncFileItemPtr &item, Proce
<< "localEntry.modtime:" << localEntry.modtime;
return;
}
if (!serverEntry.checksumHeader.isEmpty()) {
qCDebug(lcDisco) << "CSYNC_INSTRUCTION_CONFLICT: File" << item->_file << "if (!serverEntry.checksumHeader.isEmpty())";
qCDebug(lcDisco) << "CSYNC_INSTRUCTION_CONFLICT: serverEntry.size:" << serverEntry.size
@ -1425,7 +1439,7 @@ void ProcessDirectoryJob::processFileConflict(const SyncFileItemPtr &item, Proce
}
return;
}
if (!up._valid || up._contentChecksum != serverEntry.checksumHeader) {
qCDebug(lcDisco) << "CSYNC_INSTRUCTION_SYNC: File" << item->_file << "if (!up._valid && up._contentChecksum != serverEntry.checksumHeader)";
qCDebug(lcDisco) << "CSYNC_INSTRUCTION_SYNC: up._valid:" << up._valid
@ -1636,7 +1650,7 @@ bool ProcessDirectoryJob::isRename(const QString &originalPath) const
/* TODO: This was needed at some point to cover an edge case which I am no longer to reproduce and it might no longer be the case.
* Still, leaving this here just in case the edge case is caught at some point in future.
*
*
OCC::SyncJournalFileRecord base;
// are we allowed to rename?
if (!_discoveryData || !_discoveryData->_statedb || !_discoveryData->_statedb->getFileRecord(originalPath, &base)) {

View file

@ -283,6 +283,7 @@ public:
// output
QByteArray _dataFingerprint;
bool _anotherSyncNeeded = false;
int _scheduleSyncInSecs = -1;
signals:
void fatalError(const QString &errorString);

View file

@ -391,7 +391,17 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
emit itemCompleted(item);
} else {
// Update only outdated data from the disk.
if (!_journal->updateLocalMetadata(item->_file, item->_modtime, item->_size, item->_inode)) {
SyncJournalFileLockInfo lockInfo;
lockInfo._locked = item->_locked == SyncFileItem::LockStatus::LockedItem;
lockInfo._lockTime = item->_lockTime;
lockInfo._lockTimeout = item->_lockTimeout;
lockInfo._lockOwnerId = item->_lockOwnerId;
lockInfo._lockOwnerType = static_cast<qint64>(item->_lockOwnerType);
lockInfo._lockOwnerDisplayName = item->_lockOwnerDisplayName;
lockInfo._lockEditorApp = item->_lockOwnerDisplayName;
if (!_journal->updateLocalMetadata(item->_file, item->_modtime, item->_size, item->_inode, lockInfo)) {
qCWarning(lcEngine) << "Could not update local metadata for file" << item->_file;
}
}
@ -689,7 +699,11 @@ void SyncEngine::slotDiscoveryFinished()
restoreOldFiles(_syncItems);
}
if (_discoveryPhase->_anotherSyncNeeded && _anotherSyncNeeded == NoFollowUpSync) {
if (_discoveryPhase->_anotherSyncNeeded && _discoveryPhase->_scheduleSyncInSecs > 0) {
QTimer::singleShot(_discoveryPhase->_scheduleSyncInSecs * 1000, this, [this]{
this->startSync();
});
} else if (_discoveryPhase->_anotherSyncNeeded && _anotherSyncNeeded == NoFollowUpSync) {
_anotherSyncNeeded = ImmediateFollowUp;
}