mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Merge pull request #5104 from nextcloud/bugfix/doNotDeleteFilesInSyncDatabase
Bugfix/delete folders during propagation even when propagation has errors
This commit is contained in:
commit
b02f112366
@ -143,24 +143,27 @@ bool Capabilities::clientSideEncryptionAvailable() const
|
||||
}
|
||||
|
||||
const auto version = properties.value(QStringLiteral("api-version"), "1.0").toByteArray();
|
||||
qCInfo(lcServerCapabilities) << "E2EE API version:" << version;
|
||||
const auto splittedVersion = version.split('.');
|
||||
|
||||
bool ok = false;
|
||||
const auto major = !splittedVersion.isEmpty() ? splittedVersion.at(0).toInt(&ok) : 0;
|
||||
if (!ok) {
|
||||
qCWarning(lcServerCapabilities) << "Didn't understand version scheme (major), E2EE disabled";
|
||||
qCWarning(lcServerCapabilities) << "Didn't understand version scheme (major), E2EE disabled" << version;
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = false;
|
||||
const auto minor = splittedVersion.size() > 1 ? splittedVersion.at(1).toInt(&ok) : 0;
|
||||
if (!ok) {
|
||||
qCWarning(lcServerCapabilities) << "Didn't understand version scheme (minor), E2EE disabled";
|
||||
qCWarning(lcServerCapabilities) << "Didn't understand version scheme (minor), E2EE disabled" << version;
|
||||
return false;
|
||||
}
|
||||
|
||||
return major == 1 && minor >= 1;
|
||||
const auto capabilityAvailable = (major == 1 && minor >= 1);
|
||||
if (!capabilityAvailable) {
|
||||
qCInfo(lcServerCapabilities) << "Incompatible E2EE API version:" << version;
|
||||
}
|
||||
return capabilityAvailable;
|
||||
}
|
||||
|
||||
bool Capabilities::notificationsAvailable() const
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcDisco, "sync.discovery", QtInfoMsg)
|
||||
Q_LOGGING_CATEGORY(lcDisco, "nextcloud.sync.discovery", QtInfoMsg)
|
||||
|
||||
void ProcessDirectoryJob::start()
|
||||
{
|
||||
@ -615,24 +615,6 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
|
||||
// Unknown in db: new file on the server
|
||||
Q_ASSERT(!dbEntry.isValid());
|
||||
|
||||
if (!serverEntry.renameName.isEmpty()) {
|
||||
item->_renameTarget = _dirItem ? _dirItem->_file + "/" + serverEntry.renameName : serverEntry.renameName;
|
||||
item->_originalFile = path._original;
|
||||
item->_modtime = serverEntry.modtime;
|
||||
item->_size = serverEntry.size;
|
||||
item->_instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
item->_direction = SyncFileItem::Up;
|
||||
item->_fileId = serverEntry.fileId;
|
||||
item->_remotePerm = serverEntry.remotePerm;
|
||||
item->_isShared = serverEntry.remotePerm.hasPermission(RemotePermissions::IsShared);
|
||||
item->_lastShareStateFetchedTimestmap = QDateTime::currentMSecsSinceEpoch();
|
||||
item->_etag = serverEntry.etag;
|
||||
item->_type = serverEntry.isDirectory ? CSyncEnums::ItemTypeDirectory : CSyncEnums::ItemTypeFile;
|
||||
|
||||
processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer);
|
||||
return;
|
||||
}
|
||||
|
||||
item->_instruction = CSYNC_INSTRUCTION_NEW;
|
||||
item->_direction = SyncFileItem::Down;
|
||||
item->_modtime = serverEntry.modtime;
|
||||
@ -881,41 +863,6 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
|
||||
processFileFinalize(item, path, recurse, recurseQueryLocal, recurseQueryServer);
|
||||
};
|
||||
|
||||
auto handleInvalidSpaceRename = [&] (SyncFileItem::Direction direction) {
|
||||
if (_dirItem) {
|
||||
path._target = _dirItem->_file + "/" + localEntry.renameName;
|
||||
} else {
|
||||
path._target = localEntry.renameName;
|
||||
}
|
||||
OCC::SyncJournalFileRecord base;
|
||||
if (!_discoveryData->_statedb->getFileRecordByInode(localEntry.inode, &base)) {
|
||||
dbError();
|
||||
return;
|
||||
}
|
||||
const auto originalPath = base.path();
|
||||
const auto adjustedOriginalPath = _discoveryData->adjustRenamedPath(originalPath, SyncFileItem::Down);
|
||||
_discoveryData->_renamedItemsLocal.insert(originalPath, path._target);
|
||||
item->_renameTarget = path._target;
|
||||
path._server = adjustedOriginalPath;
|
||||
if (_dirItem) {
|
||||
item->_file = _dirItem->_file + "/" + localEntry.name;
|
||||
} else {
|
||||
item->_file = localEntry.name;
|
||||
}
|
||||
path._original = originalPath;
|
||||
item->_originalFile = path._original;
|
||||
item->_modtime = base.isValid() ? base._modtime : localEntry.modtime;
|
||||
item->_inode = base.isValid() ? base._inode : localEntry.inode;
|
||||
item->_instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
item->_direction = direction;
|
||||
item->_fileId = base.isValid() ? base._fileId : QByteArray{};
|
||||
item->_remotePerm = base.isValid() ? base._remotePerm : RemotePermissions{};
|
||||
item->_etag = base.isValid() ? base._etag : QByteArray{};
|
||||
item->_type = base.isValid() ? base._type : localEntry.type;
|
||||
item->_isShared = base.isValid() ? base._isShared : false;
|
||||
item->_lastShareStateFetchedTimestmap = base.isValid() ? base._lastShareStateFetchedTimestmap : 0;
|
||||
};
|
||||
|
||||
if (!localEntry.isValid()) {
|
||||
if (_queryLocal == ParentNotChanged && dbEntry.isValid()) {
|
||||
// Not modified locally (ParentNotChanged)
|
||||
@ -1000,8 +947,6 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
|
||||
|| _discoveryData->_syncOptions._vfs->needsMetadataUpdate(*item))) {
|
||||
item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
item->_direction = SyncFileItem::Down;
|
||||
} else if (!localEntry.renameName.isEmpty()) {
|
||||
handleInvalidSpaceRename(SyncFileItem::Up);
|
||||
}
|
||||
} else if (!typeChange && isVfsWithSuffix()
|
||||
&& dbEntry.isVirtualFile() && !localEntry.isVirtualFile
|
||||
@ -1097,16 +1042,6 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!localEntry.renameName.isEmpty()) {
|
||||
handleInvalidSpaceRename(SyncFileItem::Down);
|
||||
item->_instruction = CSYNC_INSTRUCTION_NEW;
|
||||
item->_direction = SyncFileItem::Up;
|
||||
item->_originalFile = item->_file;
|
||||
item->_file = item->_renameTarget;
|
||||
finalize();
|
||||
return;
|
||||
}
|
||||
|
||||
// New local file or rename
|
||||
item->_instruction = CSYNC_INSTRUCTION_NEW;
|
||||
item->_direction = SyncFileItem::Up;
|
||||
|
||||
@ -49,7 +49,6 @@ struct RemoteInfo
|
||||
{
|
||||
/** FileName of the entry (this does not contains any directory or path, just the plain name */
|
||||
QString name;
|
||||
QString renameName;
|
||||
QByteArray etag;
|
||||
QByteArray fileId;
|
||||
QByteArray checksumHeader;
|
||||
@ -79,7 +78,6 @@ struct LocalInfo
|
||||
{
|
||||
/** FileName of the entry (this does not contains any directory or path, just the plain name */
|
||||
QString name;
|
||||
QString renameName;
|
||||
time_t modtime = 0;
|
||||
int64_t size = 0;
|
||||
uint64_t inode = 0;
|
||||
|
||||
@ -594,7 +594,7 @@ void OwncloudPropagator::start(SyncFileItemVector &&items)
|
||||
}
|
||||
|
||||
foreach (PropagatorJob *it, directoriesToRemove) {
|
||||
_rootJob->_dirDeletionJobs.appendJob(it);
|
||||
_rootJob->appendDirDeletionJob(it);
|
||||
}
|
||||
|
||||
connect(_rootJob.data(), &PropagatorJob::finished, this, &OwncloudPropagator::emitFinished);
|
||||
@ -1292,6 +1292,11 @@ qint64 PropagateRootDirectory::committedDiskSpace() const
|
||||
return _subJobs.committedDiskSpace() + _dirDeletionJobs.committedDiskSpace();
|
||||
}
|
||||
|
||||
void PropagateRootDirectory::appendDirDeletionJob(PropagatorJob *job)
|
||||
{
|
||||
_dirDeletionJobs.appendJob(job);
|
||||
}
|
||||
|
||||
bool PropagateRootDirectory::scheduleSelfOrChild()
|
||||
{
|
||||
qCInfo(lcRootDirectory()) << "scheduleSelfOrChild" << _state << "pending uploads" << propagator()->delayedTasks().size() << "subjobs state" << _subJobs._state;
|
||||
@ -1327,6 +1332,7 @@ void PropagateRootDirectory::slotSubJobsFinished(SyncFileItem::Status status)
|
||||
|
||||
if (status != SyncFileItem::Success
|
||||
&& status != SyncFileItem::Restoration
|
||||
&& status != SyncFileItem::BlacklistedError
|
||||
&& status != SyncFileItem::Conflict) {
|
||||
if (_state != Finished) {
|
||||
// Synchronously abort
|
||||
@ -1338,11 +1344,37 @@ void PropagateRootDirectory::slotSubJobsFinished(SyncFileItem::Status status)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_errorStatus == SyncFileItem::NoStatus) {
|
||||
switch (status) {
|
||||
case SyncFileItem::NoStatus:
|
||||
case SyncFileItem::FatalError:
|
||||
case SyncFileItem::NormalError:
|
||||
case SyncFileItem::SoftError:
|
||||
case SyncFileItem::Conflict:
|
||||
case SyncFileItem::FileIgnored:
|
||||
case SyncFileItem::FileLocked:
|
||||
case SyncFileItem::Restoration:
|
||||
case SyncFileItem::FileNameInvalid:
|
||||
case SyncFileItem::FileNameClash:
|
||||
case SyncFileItem::DetailError:
|
||||
case SyncFileItem::Success:
|
||||
break;
|
||||
case SyncFileItem::BlacklistedError:
|
||||
_errorStatus = SyncFileItem::BlacklistedError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
propagator()->scheduleNextJob();
|
||||
}
|
||||
|
||||
void PropagateRootDirectory::slotDirDeletionJobsFinished(SyncFileItem::Status status)
|
||||
{
|
||||
if (_errorStatus != SyncFileItem::NoStatus && status == SyncFileItem::Success) {
|
||||
qCInfo(lcPropagator) << "PropagateRootDirectory::slotDirDeletionJobsFinished" << "reporting previous error" << _errorStatus;
|
||||
status = _errorStatus;
|
||||
}
|
||||
|
||||
_state = Finished;
|
||||
qCInfo(lcPropagator) << "PropagateRootDirectory::slotDirDeletionJobsFinished" << "emit finished" << status;
|
||||
emit finished(status);
|
||||
|
||||
@ -365,8 +365,6 @@ class OWNCLOUDSYNC_EXPORT PropagateRootDirectory : public PropagateDirectory
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PropagatorCompositeJob _dirDeletionJobs;
|
||||
|
||||
explicit PropagateRootDirectory(OwncloudPropagator *propagator);
|
||||
|
||||
bool scheduleSelfOrChild() override;
|
||||
@ -375,6 +373,9 @@ public:
|
||||
|
||||
[[nodiscard]] qint64 committedDiskSpace() const override;
|
||||
|
||||
public slots:
|
||||
void appendDirDeletionJob(PropagatorJob *job);
|
||||
|
||||
private slots:
|
||||
void slotSubJobsFinished(SyncFileItem::Status status) override;
|
||||
void slotDirDeletionJobsFinished(SyncFileItem::Status status);
|
||||
@ -382,6 +383,10 @@ private slots:
|
||||
private:
|
||||
|
||||
bool scheduleDelayedJobs();
|
||||
|
||||
PropagatorCompositeJob _dirDeletionJobs;
|
||||
|
||||
SyncFileItem::Status _errorStatus = SyncFileItem::Status::NoStatus;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -890,6 +890,29 @@ private slots:
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void testRenameParallelismWithBlacklist()
|
||||
{
|
||||
constexpr auto testFileName = "blackListFile";
|
||||
FakeFolder fakeFolder{ FileInfo{} };
|
||||
fakeFolder.remoteModifier().mkdir("A");
|
||||
fakeFolder.remoteModifier().insert("A/file");
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.remoteModifier().insert(testFileName);
|
||||
fakeFolder.serverErrorPaths().append(testFileName, 500); // will be blacklisted
|
||||
QVERIFY(!fakeFolder.syncOnce());
|
||||
|
||||
fakeFolder.remoteModifier().mkdir("B");
|
||||
fakeFolder.remoteModifier().rename("A/file", "B/file");
|
||||
fakeFolder.remoteModifier().remove("A");
|
||||
|
||||
QVERIFY(!fakeFolder.syncOnce());
|
||||
auto folderA = fakeFolder.currentLocalState().find("A");
|
||||
QCOMPARE(folderA, nullptr);
|
||||
}
|
||||
|
||||
void testMovedWithError_data()
|
||||
{
|
||||
QTest::addColumn<Vfs::Mode>("vfsMode");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user