Merge pull request #7201 from nextcloud/backport/7193/stable-3.14

[stable-3.14] Bugfix/fix upload locked files
This commit is contained in:
Matthieu Gallien 2024-09-25 15:56:30 +02:00 committed by GitHub
commit b6211ff082
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 43 additions and 13 deletions

View file

@ -49,7 +49,7 @@ Q_LOGGING_CATEGORY(lcDb, "nextcloud.sync.database", QtInfoMsg)
#define GET_FILE_RECORD_QUERY \
"SELECT path, inode, modtime, type, md5, fileid, remotePerm, filesize," \
" ignoredChildrenRemote, contentchecksumtype.name || ':' || contentChecksum, e2eMangledName, isE2eEncrypted, " \
" lock, lockOwnerDisplayName, lockOwnerId, lockType, lockOwnerEditor, lockTime, lockTimeout, isShared, lastShareStateFetchedTimestmap, sharedByMe" \
" lock, lockOwnerDisplayName, lockOwnerId, lockType, lockOwnerEditor, lockTime, lockTimeout, lockToken, isShared, lastShareStateFetchedTimestmap, sharedByMe" \
" FROM metadata" \
" LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id"
@ -74,9 +74,10 @@ static void fillFileRecordFromGetQuery(SyncJournalFileRecord &rec, SqlQuery &que
rec._lockstate._lockEditorApp = query.stringValue(16);
rec._lockstate._lockTime = query.int64Value(17);
rec._lockstate._lockTimeout = query.int64Value(18);
rec._isShared = query.intValue(19) > 0;
rec._lastShareStateFetchedTimestamp = query.int64Value(20);
rec._sharedByMe = query.intValue(21) > 0;
rec._lockstate._lockToken = query.stringValue(19);
rec._isShared = query.intValue(20) > 0;
rec._lastShareStateFetchedTimestamp = query.int64Value(21);
rec._sharedByMe = query.intValue(22) > 0;
}
static QByteArray defaultJournalMode(const QString &dbPath)
@ -826,6 +827,7 @@ bool SyncJournalDb::updateMetadataTableStructure()
addColumn(QStringLiteral("lockOwnerEditor"), QStringLiteral("TEXT"));
addColumn(QStringLiteral("lockTime"), QStringLiteral("INTEGER"));
addColumn(QStringLiteral("lockTimeout"), QStringLiteral("INTEGER"));
addColumn(QStringLiteral("lockToken"), QStringLiteral("TEXT"));
SqlQuery query(_db);
query.prepare("CREATE INDEX IF NOT EXISTS caseconflicts_basePath ON caseconflicts(basePath);");
@ -987,8 +989,8 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
const auto query = _queryManager.get(PreparedSqlQueryManager::SetFileRecordQuery, QByteArrayLiteral("INSERT OR REPLACE INTO metadata "
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote, "
"contentChecksum, contentChecksumTypeId, e2eMangledName, isE2eEncrypted, lock, lockType, lockOwnerDisplayName, lockOwnerId, "
"lockOwnerEditor, lockTime, lockTimeout, isShared, lastShareStateFetchedTimestmap, sharedByMe) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28);"),
"lockOwnerEditor, lockTime, lockTimeout, lockToken, isShared, lastShareStateFetchedTimestmap, sharedByMe) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29);"),
_db);
if (!query) {
qCDebug(lcDb) << "database error:" << query->error();
@ -1020,9 +1022,10 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
query->bindValue(23, record._lockstate._lockEditorApp);
query->bindValue(24, record._lockstate._lockTime);
query->bindValue(25, record._lockstate._lockTimeout);
query->bindValue(26, record._isShared);
query->bindValue(27, record._lastShareStateFetchedTimestamp);
query->bindValue(28, record._sharedByMe);
query->bindValue(26, record._lockstate._lockToken);
query->bindValue(27, record._isShared);
query->bindValue(28, record._lastShareStateFetchedTimestamp);
query->bindValue(29, record._sharedByMe);
if (!query->exec()) {
qCDebug(lcDb) << "database error:" << query->error();
@ -1616,7 +1619,7 @@ bool SyncJournalDb::updateLocalMetadata(const QString &filename,
const auto query = _queryManager.get(PreparedSqlQueryManager::SetFileRecordLocalMetadataQuery, QByteArrayLiteral("UPDATE metadata"
" SET inode=?2, modtime=?3, filesize=?4, lock=?5, lockType=?6,"
" lockOwnerDisplayName=?7, lockOwnerId=?8, lockOwnerEditor = ?9,"
" lockTime=?10, lockTimeout=?11"
" lockTime=?10, lockTimeout=?11, lockToken=?12"
" WHERE phash == ?1;"),
_db);
if (!query) {
@ -1635,6 +1638,7 @@ bool SyncJournalDb::updateLocalMetadata(const QString &filename,
query->bindValue(9, lockInfo._lockEditorApp);
query->bindValue(10, lockInfo._lockTime);
query->bindValue(11, lockInfo._lockTimeout);
query->bindValue(12, lockInfo._lockToken);
if (!query->exec()) {
qCDebug(lcDb) << "database error:" << query->error();
return false;

View file

@ -39,6 +39,7 @@ struct SyncJournalFileLockInfo {
QString _lockEditorApp;
qint64 _lockTime = 0;
qint64 _lockTimeout = 0;
QString _lockToken;
};
/**

View file

@ -712,6 +712,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
item->_lockEditorApp = serverEntry.lockEditorApp;
item->_lockTime = serverEntry.lockTime;
item->_lockTimeout = serverEntry.lockTimeout;
item->_lockToken = serverEntry.lockToken;
qCDebug(lcDisco()) << "item lock for:" << item->_file
<< item->_locked
@ -720,7 +721,8 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
<< item->_lockOwnerType
<< item->_lockEditorApp
<< item->_lockTime
<< item->_lockTimeout;
<< item->_lockTimeout
<< item->_lockToken;
// Check for missing server data
{

View file

@ -415,7 +415,8 @@ void DiscoverySingleDirectoryJob::start()
<< "http://nextcloud.org/ns:lock-owner-type"
<< "http://nextcloud.org/ns:lock-owner-editor"
<< "http://nextcloud.org/ns:lock-time"
<< "http://nextcloud.org/ns:lock-timeout";
<< "http://nextcloud.org/ns:lock-timeout"
<< "http://nextcloud.org/ns:lock-token";
}
props << "http://nextcloud.org/ns:is-mount-root";
@ -547,7 +548,9 @@ static void propertyMapToRemoteInfo(const QMap<QString, QString> &map, RemotePer
result.lockTimeout = 0;
}
}
if (property == "lock-token") {
result.lockToken = value;
}
}
if (result.isDirectory && map.contains("size")) {

View file

@ -86,6 +86,7 @@ struct RemoteInfo
QString lockEditorApp;
qint64 lockTime = 0;
qint64 lockTimeout = 0;
QString lockToken;
};
struct LocalInfo

View file

@ -115,6 +115,7 @@ void LockFileJob::setFileRecordLocked(SyncJournalFileRecord &record) const
record._lockstate._lockEditorApp = _editorName;
record._lockstate._lockTime = _lockTime;
record._lockstate._lockTimeout = _lockTimeout;
record._lockstate._lockToken = _lockToken;
if (!_etag.isEmpty()) {
record._etag = _etag;
}
@ -129,6 +130,7 @@ void LockFileJob::resetState()
_userId.clear();
_lockTime = 0;
_lockTimeout = 0;
_lockToken.clear();
}
SyncJournalFileRecord LockFileJob::handleReply()
@ -241,6 +243,8 @@ void LockFileJob::decodeStartElement(const QString &name,
_editorName = reader.readElementText();
} else if (name == QStringLiteral("getetag")) {
_etag = reader.readElementText().toUtf8();
} else if (name == QStringLiteral("lock-token")) {
_lockToken = reader.readElementText();
}
}

View file

@ -59,6 +59,7 @@ private:
QByteArray _etag;
qint64 _lockTime = 0;
qint64 _lockTimeout = 0;
QString _lockToken;
QString _remoteSyncPathWithTrailingSlash;
QString _localSyncPath;
};

View file

@ -328,6 +328,9 @@ void PropagateUploadFileNG::finishUpload()
const auto fileSize = _fileToUpload._size;
headers[QByteArrayLiteral("OC-Total-Length")] = QByteArray::number(fileSize);
if (_item->_locked == SyncFileItem::LockStatus::LockedItem) {
headers[QByteArrayLiteral("If")] = (QLatin1String("<") + propagator()->account()->davUrl().toString() + _fileToUpload._file + "> (<opaquelocktoken:" + _item->_lockToken.toUtf8() + ">)").toUtf8();
}
const auto job = new MoveJob(propagator()->account(), Utility::concatUrlPath(chunkUploadFolderUrl(), "/.file"), destination, headers, this);
_jobs.append(job);

View file

@ -102,6 +102,10 @@ void PropagateUploadFileV1::startNextChunk()
QString path = _fileToUpload._file;
if (_item->_locked == SyncFileItem::LockStatus::LockedItem) {
headers[QByteArrayLiteral("If")] = (QLatin1String("<") + propagator()->account()->davUrl().toString() + _fileToUpload._file + "> (<opaquelocktoken:" + _item->_lockToken.toUtf8() + ">)").toUtf8();
}
qint64 chunkStart = 0;
qint64 currentChunkSize = fileSize;
bool isFinalChunk = false;

View file

@ -440,6 +440,7 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
lockInfo._lockOwnerType = static_cast<qint64>(item->_lockOwnerType);
lockInfo._lockOwnerDisplayName = item->_lockOwnerDisplayName;
lockInfo._lockEditorApp = item->_lockOwnerDisplayName;
lockInfo._lockToken = item->_lockToken;
if (!_journal->updateLocalMetadata(item->_file, item->_modtime, item->_size, item->_inode, lockInfo)) {
qCWarning(lcEngine) << "Could not update local metadata for file" << item->_file;

View file

@ -125,6 +125,7 @@ SyncJournalFileRecord SyncFileItem::toSyncJournalFileRecordWithInode(const QStri
rec._lockstate._lockEditorApp = _lockEditorApp;
rec._lockstate._lockTime = _lockTime;
rec._lockstate._lockTimeout = _lockTimeout;
rec._lockstate._lockToken = _lockToken;
// Update the inode if possible
rec._inode = _inode;
@ -163,6 +164,7 @@ SyncFileItemPtr SyncFileItem::fromSyncJournalFileRecord(const SyncJournalFileRec
item->_lockEditorApp = rec._lockstate._lockEditorApp;
item->_lockTime = rec._lockstate._lockTime;
item->_lockTimeout = rec._lockstate._lockTimeout;
item->_lockToken = rec._lockstate._lockToken;
item->_sharedByMe = rec._sharedByMe;
item->_isShared = rec._isShared;
item->_lastShareStateFetchedTimestamp = rec._lastShareStateFetchedTimestamp;
@ -220,6 +222,8 @@ SyncFileItemPtr SyncFileItem::fromProperties(const QString &filePath, const QMap
item->_lockTimeout = ok ? intConvertedValue : 0;
}
item->_lockToken = properties.value(QStringLiteral("lock-token"));
const auto date = QDateTime::fromString(properties.value(QStringLiteral("getlastmodified")), Qt::RFC2822Date);
Q_ASSERT(date.isValid());
if (date.toSecsSinceEpoch() > 0) {
@ -250,6 +254,7 @@ void SyncFileItem::updateLockStateFromDbRecord(const SyncJournalFileRecord &dbRe
_lockEditorApp = dbRecord._lockstate._lockEditorApp;
_lockTime = dbRecord._lockstate._lockTime;
_lockTimeout = dbRecord._lockstate._lockTimeout;
_lockToken = dbRecord._lockstate._lockToken;
}
}

View file

@ -326,6 +326,7 @@ public:
QString _lockEditorApp;
qint64 _lockTime = 0;
qint64 _lockTimeout = 0;
QString _lockToken;
bool _isShared = false;
time_t _lastShareStateFetchedTimestamp = 0;