mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-27 09:30:13 +03:00
Merge pull request #3449 from nextcloud/bugfix/fix-vfs-crash-and-false-conflict-on-local-new
Fix VFS crash and false conflict on local new.
This commit is contained in:
commit
dca7b8d8d2
2 changed files with 62 additions and 38 deletions
|
@ -126,6 +126,8 @@ public:
|
|||
ASSERT(_isError);
|
||||
return std::move(_error);
|
||||
}
|
||||
|
||||
bool isValid() const { return !_isError; }
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
|
|
@ -896,46 +896,68 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
|
|||
auto postProcessLocalNew = [item, localEntry, path, this]() {
|
||||
// TODO: We may want to execute the same logic for non-VFS mode, as, moving/renaming the same folder by 2 or more clients at the same time is not possible in Web UI.
|
||||
// Keeping it like this (for VFS files and folders only) just to fix a user issue.
|
||||
const auto isVfsEnabled = _discoveryData->_syncOptions._vfs && _discoveryData->_syncOptions._vfs->mode() != Vfs::Off;
|
||||
if (localEntry.isVirtualFile || (localEntry.isDirectory && isVfsEnabled)) {
|
||||
// must be a dehydrated placeholder
|
||||
const bool isFilePlaceHolder = !localEntry.isDirectory && _discoveryData->_syncOptions._vfs->isDehydratedPlaceholder(_discoveryData->_localDir + path._local);
|
||||
|
||||
// a folder must be online-only (no files should be hydrated)
|
||||
const bool isFolderPlaceholder = localEntry.isDirectory && *_discoveryData->_syncOptions._vfs->availability(path._local) == VfsItemAvailability::OnlineOnly;
|
||||
|
||||
Q_ASSERT(item->_instruction == CSYNC_INSTRUCTION_NEW);
|
||||
if (item->_instruction != CSYNC_INSTRUCTION_NEW) {
|
||||
qCWarning(lcDisco) << "Wiping virtual file without db entry for" << path._local << ". But, item->_instruction is" << item->_instruction;
|
||||
}
|
||||
|
||||
// must be a file placeholder or an online-only folder placeholder
|
||||
if (isFilePlaceHolder || isFolderPlaceholder) {
|
||||
if (isFolderPlaceholder) {
|
||||
qCInfo(lcDisco) << "Wiping virtual folder without db entry for" << path._local;
|
||||
} else {
|
||||
qCInfo(lcDisco) << "Wiping virtual file without db entry for" << path._local;
|
||||
}
|
||||
item->_instruction = CSYNC_INSTRUCTION_REMOVE;
|
||||
item->_direction = SyncFileItem::Down;
|
||||
// this flag needs to be unset, otherwise a folder would get marked as new in the processSubJobs
|
||||
_childModified = false;
|
||||
if (isFolderPlaceholder && _discoveryData) {
|
||||
emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a folder. It's going to get cleared!"), path._local);
|
||||
}
|
||||
} else {
|
||||
if (localEntry.isDirectory && !isFolderPlaceholder) {
|
||||
qCInfo(lcDisco) << "Virtual directory without db entry for" << path._local << "but it contains hydrated file(s), so let's keep it and reupload.";
|
||||
if (_discoveryData) {
|
||||
emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading some files to a folder. Those, conflicted, are going to get cleared!"), path._local);
|
||||
}
|
||||
return;
|
||||
}
|
||||
qCWarning(lcDisco) << "Virtual file without db entry for" << path._local
|
||||
<< "but looks odd, keeping";
|
||||
item->_instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
}
|
||||
if (!(_discoveryData && _discoveryData->_syncOptions._vfs && _discoveryData->_syncOptions._vfs->mode() != Vfs::Off)) {
|
||||
// for VFS files and folders only
|
||||
return;
|
||||
}
|
||||
|
||||
if (!localEntry.isVirtualFile && !localEntry.isDirectory) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(item->_instruction == CSYNC_INSTRUCTION_NEW);
|
||||
if (item->_instruction != CSYNC_INSTRUCTION_NEW) {
|
||||
qCWarning(lcDisco) << "Trying to wipe a virtual item" << path._local << " with item->_instruction" << item->_instruction;
|
||||
return;
|
||||
}
|
||||
|
||||
// must be a dehydrated placeholder
|
||||
const bool isFilePlaceHolder = !localEntry.isDirectory && _discoveryData->_syncOptions._vfs->isDehydratedPlaceholder(_discoveryData->_localDir + path._local);
|
||||
|
||||
// either correct availability, or a result with error if the folder is new or otherwise has no availability set yet
|
||||
const auto folderPlaceHolderAvailability = localEntry.isDirectory ? _discoveryData->_syncOptions._vfs->availability(path._local) : Vfs::AvailabilityResult(Vfs::AvailabilityError::NoSuchItem);
|
||||
|
||||
const auto folderPinState = localEntry.isDirectory ? _discoveryData->_syncOptions._vfs->pinState(path._local) : Optional<PinStateEnums::PinState>(PinState::Unspecified);
|
||||
|
||||
if (!isFilePlaceHolder && !folderPlaceHolderAvailability.isValid() && !folderPinState.isValid()) {
|
||||
// not a file placeholder and not a synced folder placeholder (new local folder)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto isFolderPinStateOnlineOnly = (folderPinState.isValid() && *folderPinState == PinState::OnlineOnly);
|
||||
|
||||
const auto isfolderPlaceHolderAvailabilityOnlineOnly = (folderPlaceHolderAvailability.isValid() && *folderPlaceHolderAvailability == VfsItemAvailability::OnlineOnly);
|
||||
|
||||
// a folder is considered online-only if: no files are hydrated, or, if it's an empty folder
|
||||
const auto isOnlineOnlyFolder = isfolderPlaceHolderAvailabilityOnlineOnly || !folderPlaceHolderAvailability && isFolderPinStateOnlineOnly;
|
||||
|
||||
if (!isFilePlaceHolder && !isOnlineOnlyFolder) {
|
||||
if (localEntry.isDirectory && folderPlaceHolderAvailability.isValid() && !isOnlineOnlyFolder) {
|
||||
// a VFS folder but is not online0only (has some files hydrated)
|
||||
qCInfo(lcDisco) << "Virtual directory without db entry for" << path._local << "but it contains hydrated file(s), so let's keep it and reupload.";
|
||||
emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading some files to a folder. Those, conflicted, are going to get cleared!"), path._local);
|
||||
return;
|
||||
}
|
||||
qCWarning(lcDisco) << "Virtual file without db entry for" << path._local
|
||||
<< "but looks odd, keeping";
|
||||
item->_instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOnlineOnlyFolder) {
|
||||
// if we're wiping a folder, we will only get this function called once and will wipe a folder along with it's files and also display one error in GUI
|
||||
qCInfo(lcDisco) << "Wiping virtual folder without db entry for" << path._local;
|
||||
emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a folder. It's going to get cleared!"), path._local);
|
||||
} else {
|
||||
qCInfo(lcDisco) << "Wiping virtual file without db entry for" << path._local;
|
||||
emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a file. It's going to get removed!"), path._local);
|
||||
}
|
||||
item->_instruction = CSYNC_INSTRUCTION_REMOVE;
|
||||
item->_direction = SyncFileItem::Down;
|
||||
// this flag needs to be unset, otherwise a folder would get marked as new in the processSubJobs
|
||||
_childModified = false;
|
||||
};
|
||||
|
||||
// Check if it is a move
|
||||
|
|
Loading…
Reference in a new issue