From: Christian Kamm Date: Wed, 17 Oct 2018 08:43:25 +0000 (+0200) Subject: Discovery: easy conditions first in processFileAnalyzeRemoteInfo X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~479 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=a2839bd40a0f3f4a319473818d32ed12e7186b07;p=nextcloud-desktop.git Discovery: easy conditions first in processFileAnalyzeRemoteInfo Removing two levels of indent that way --- diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index 25d9bfa17..ddefeeed6 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -438,203 +438,219 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo( item->_previousModtime = localEntry.modtime; item->_directDownloadUrl = serverEntry.directDownloadUrl; item->_directDownloadCookies = serverEntry.directDownloadCookies; - if (!dbEntry.isValid()) { // New file on the server - item->_instruction = CSYNC_INSTRUCTION_NEW; - item->_direction = SyncFileItem::Down; - item->_modtime = serverEntry.modtime; - item->_size = serverEntry.size; - - auto postProcessServerNew = [item, this, path, serverEntry, localEntry, dbEntry] { - if (item->isDirectory()) { - _pendingAsyncJobs++; - _discoveryData->checkSelectiveSyncNewFolder(path._server, serverEntry.remotePerm, - [=](bool result) { - --_pendingAsyncJobs; - if (!result) { - processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer); - } - QTimer::singleShot(0, _discoveryData, &DiscoveryPhase::scheduleMoreJobs); - }); - return; - } - // Turn new remote files into virtual files if the option is enabled. - if (_discoveryData->_syncOptions._newFilesAreVirtual && item->_type == ItemTypeFile) { - item->_type = ItemTypeVirtualFile; - item->_file.append(_discoveryData->_syncOptions._virtualFileSuffix); - } - processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer); - }; - - if (!localEntry.isValid()) { - // Check for renames (if there is a file with the same file id) - bool done = false; - bool async = false; - // This function will be executed for every candidate - auto renameCandidateProcessing = [&](const OCC::SyncJournalFileRecord &base) { - if (done) - return; - if (!base.isValid()) - return; - if (base._type == ItemTypeVirtualFileDownload) { - // Remote rename of a virtual file we have locally scheduled - // for download. We just consider this NEW but mark it for download. - item->_type = ItemTypeVirtualFileDownload; - done = true; - return; - } + // The file is known in the db already + if (dbEntry.isValid()) { + if (serverEntry.isDirectory != (dbEntry._type == ItemTypeDirectory)) { + // If the type of the entity changed, it's like NEW, but + // needs to delete the other entity first. + item->_instruction = CSYNC_INSTRUCTION_TYPE_CHANGE; + item->_direction = SyncFileItem::Down; + item->_modtime = serverEntry.modtime; + item->_size = serverEntry.size; + } else if (dbEntry._type == ItemTypeVirtualFileDownload) { + item->_direction = SyncFileItem::Down; + item->_instruction = CSYNC_INSTRUCTION_NEW; + item->_type = ItemTypeVirtualFileDownload; + item->_file = path._target; + if (item->_file.endsWith(_discoveryData->_syncOptions._virtualFileSuffix)) + item->_file.chop(_discoveryData->_syncOptions._virtualFileSuffix.size()); + } else if (dbEntry._etag != serverEntry.etag) { + item->_direction = SyncFileItem::Down; + item->_modtime = serverEntry.modtime; + item->_size = serverEntry.size; + if (serverEntry.isDirectory) { + ENFORCE(dbEntry._type == ItemTypeDirectory); + item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + } else if (!localEntry.isValid() && _queryLocal != ParentNotChanged) { + // Deleted locally, changed on server + item->_instruction = CSYNC_INSTRUCTION_NEW; + } else { + item->_instruction = CSYNC_INSTRUCTION_SYNC; + } + } else if (dbEntry._remotePerm != serverEntry.remotePerm || dbEntry._fileId != serverEntry.fileId) { + item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + item->_direction = SyncFileItem::Down; + } else { + processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, ParentNotChanged); + return; + } - // Some things prohibit rename detection entirely. - // Since we don't do the same checks again in reconcile, we can't - // just skip the candidate, but have to give up completely. - if (base._type != item->_type && base._type != ItemTypeVirtualFile) { - qCInfo(lcDisco, "file types different, not a rename"); - done = true; - return; - } - if (!serverEntry.isDirectory && base._etag != serverEntry.etag) { - /* File with different etag, don't do a rename, but download the file again */ - qCInfo(lcDisco, "file etag different, not a rename"); - done = true; - return; - } + processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer); + return; + } - // Now we know there is a sane rename candidate. - QString originalPath = QString::fromUtf8(base._path); + // Unknown in db: new file on the server + Q_ASSERT(!dbEntry.isValid()); + + item->_instruction = CSYNC_INSTRUCTION_NEW; + item->_direction = SyncFileItem::Down; + item->_modtime = serverEntry.modtime; + item->_size = serverEntry.size; + + auto postProcessServerNew = [item, this, path, serverEntry, localEntry, dbEntry] { + if (item->isDirectory()) { + _pendingAsyncJobs++; + _discoveryData->checkSelectiveSyncNewFolder(path._server, serverEntry.remotePerm, + [=](bool result) { + --_pendingAsyncJobs; + if (!result) { + processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer); + } + QTimer::singleShot(0, _discoveryData, &DiscoveryPhase::scheduleMoreJobs); + }); + return; + } + // Turn new remote files into virtual files if the option is enabled. + if (_discoveryData->_syncOptions._newFilesAreVirtual && item->_type == ItemTypeFile) { + item->_type = ItemTypeVirtualFile; + item->_file.append(_discoveryData->_syncOptions._virtualFileSuffix); + } + processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer); + }; - // Rename of a virtual file - if (base._type == ItemTypeVirtualFile && item->_type == ItemTypeFile) { - // Ignore if the base is a virtual files - return; - } + // Potential NEW/NEW conflict is handled in AnalyzeLocal + if (localEntry.isValid()) { + postProcessServerNew(); + return; + } - if (_discoveryData->_renamedItems.contains(originalPath)) { - qCInfo(lcDisco, "folder already has a rename entry, skipping"); - return; - } + // Not in db or locally: either new or a rename + Q_ASSERT(!dbEntry.isValid() && !localEntry.isValid()); - /* A remote rename can also mean Encryption Mangled Name. - * if we find one of those in the database, we ignore it. - */ - if (!base._e2eMangledName.isEmpty()) { - qCWarning(lcDisco, "Encrypted file can not rename"); - done = true; - return; - } + // Check for renames (if there is a file with the same file id) + bool done = false; + bool async = false; + // This function will be executed for every candidate + auto renameCandidateProcessing = [&](const OCC::SyncJournalFileRecord &base) { + if (done) + return; + if (!base.isValid()) + return; - if (item->_type == ItemTypeFile) { - csync_file_stat_t buf; - if (csync_vio_local_stat((_discoveryData->_localDir + originalPath).toUtf8(), &buf)) { - qCInfo(lcDisco) << "Local file does not exist anymore." << originalPath; - return; - } - if (buf.modtime != base._modtime || buf.size != base._fileSize || buf.type != ItemTypeFile) { - qCInfo(lcDisco) << "File has changed locally, not a rename." << originalPath; - return; - } - } else { - if (!QFileInfo(_discoveryData->_localDir + originalPath).isDir()) { - qCInfo(lcDisco) << "Local directory does not exist anymore." << originalPath; - return; - } - } + if (base._type == ItemTypeVirtualFileDownload) { + // Remote rename of a virtual file we have locally scheduled + // for download. We just consider this NEW but mark it for download. + item->_type = ItemTypeVirtualFileDownload; + done = true; + return; + } - bool wasDeletedOnServer = _discoveryData->findAndCancelDeletedJob(originalPath).first; + // Some things prohibit rename detection entirely. + // Since we don't do the same checks again in reconcile, we can't + // just skip the candidate, but have to give up completely. + if (base._type != item->_type && base._type != ItemTypeVirtualFile) { + qCInfo(lcDisco, "file types different, not a rename"); + done = true; + return; + } + if (!serverEntry.isDirectory && base._etag != serverEntry.etag) { + /* File with different etag, don't do a rename, but download the file again */ + qCInfo(lcDisco, "file etag different, not a rename"); + done = true; + return; + } - auto postProcessRename = [this, item, base, originalPath](PathTuple &path) { - auto adjustedOriginalPath = _discoveryData->adjustRenamedPath(originalPath); - _discoveryData->_renamedItems.insert(originalPath, path._target); - item->_modtime = base._modtime; - item->_inode = base._inode; - item->_instruction = CSYNC_INSTRUCTION_RENAME; - item->_direction = SyncFileItem::Down; - item->_renameTarget = path._target; - item->_file = adjustedOriginalPath; - item->_originalFile = originalPath; - path._original = originalPath; - path._local = adjustedOriginalPath; - qCInfo(lcDisco) << "Rename detected (down) " << item->_file << " -> " << item->_renameTarget; - }; + // Now we know there is a sane rename candidate. + QString originalPath = QString::fromUtf8(base._path); - if (wasDeletedOnServer) { - postProcessRename(path); - done = true; - } else { - // we need to make a request to the server to know that the original file is deleted on the server - _pendingAsyncJobs++; - auto job = new RequestEtagJob(_discoveryData->_account, originalPath, this); - connect(job, &RequestEtagJob::finishedWithResult, this, [=](const Result &etag) mutable { - _pendingAsyncJobs--; - QTimer::singleShot(0, _discoveryData, &DiscoveryPhase::scheduleMoreJobs); - if (etag.errorCode() != 404 || - // Somehow another item claimed this original path, consider as if it existed - _discoveryData->_renamedItems.contains(originalPath)) { - // If the file exist or if there is another error, consider it is a new file. - postProcessServerNew(); - return; - } + // Rename of a virtual file + if (base._type == ItemTypeVirtualFile && item->_type == ItemTypeFile) { + // Ignore if the base is a virtual files + return; + } - // The file do not exist, it is a rename + if (_discoveryData->_renamedItems.contains(originalPath)) { + qCInfo(lcDisco, "folder already has a rename entry, skipping"); + return; + } - // In case the deleted item was discovered in parallel - _discoveryData->findAndCancelDeletedJob(originalPath); + /* A remote rename can also mean Encryption Mangled Name. + * if we find one of those in the database, we ignore it. + */ + if (!base._e2eMangledName.isEmpty()) { + qCWarning(lcDisco, "Encrypted file can not rename"); + done = true; + return; + } - postProcessRename(path); - processFileFinalize(item, path, item->isDirectory(), item->_instruction == CSYNC_INSTRUCTION_RENAME ? NormalQuery : ParentDontExist, _queryServer); - }); - job->start(); - done = true; // Ideally, if the origin still exist on the server, we should continue searching... but that'd be difficult - async = true; - } - }; - if (!_discoveryData->_statedb->getFileRecordsByFileId(serverEntry.fileId, renameCandidateProcessing)) { - dbError(); + if (item->_type == ItemTypeFile) { + csync_file_stat_t buf; + if (csync_vio_local_stat((_discoveryData->_localDir + originalPath).toUtf8(), &buf)) { + qCInfo(lcDisco) << "Local file does not exist anymore." << originalPath; return; } - if (async) { - return; // We went async + if (buf.modtime != base._modtime || buf.size != base._fileSize || buf.type != ItemTypeFile) { + qCInfo(lcDisco) << "File has changed locally, not a rename." << originalPath; + return; + } + } else { + if (!QFileInfo(_discoveryData->_localDir + originalPath).isDir()) { + qCInfo(lcDisco) << "Local directory does not exist anymore." << originalPath; + return; } } - if (item->_instruction == CSYNC_INSTRUCTION_NEW) { - postProcessServerNew(); - return; - } - } else if (serverEntry.isDirectory != (dbEntry._type == ItemTypeDirectory)) { - // If the type of the entity changed, it's like NEW, but - // needs to delete the other entity first. - item->_instruction = CSYNC_INSTRUCTION_TYPE_CHANGE; - item->_direction = SyncFileItem::Down; - item->_modtime = serverEntry.modtime; - item->_size = serverEntry.size; - } else if (dbEntry._type == ItemTypeVirtualFileDownload) { - item->_direction = SyncFileItem::Down; - item->_instruction = CSYNC_INSTRUCTION_NEW; - item->_type = ItemTypeVirtualFileDownload; - item->_file = path._target; - if (item->_file.endsWith(_discoveryData->_syncOptions._virtualFileSuffix)) - item->_file.chop(_discoveryData->_syncOptions._virtualFileSuffix.size()); - } else if (dbEntry._etag != serverEntry.etag) { - item->_direction = SyncFileItem::Down; - item->_modtime = serverEntry.modtime; - item->_size = serverEntry.size; - if (serverEntry.isDirectory) { - ENFORCE(dbEntry._type == ItemTypeDirectory); - item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - } else if (!localEntry.isValid() && _queryLocal != ParentNotChanged) { - // Deleted locally, changed on server - item->_instruction = CSYNC_INSTRUCTION_NEW; + bool wasDeletedOnServer = _discoveryData->findAndCancelDeletedJob(originalPath).first; + + auto postProcessRename = [this, item, base, originalPath](PathTuple &path) { + auto adjustedOriginalPath = _discoveryData->adjustRenamedPath(originalPath); + _discoveryData->_renamedItems.insert(originalPath, path._target); + item->_modtime = base._modtime; + item->_inode = base._inode; + item->_instruction = CSYNC_INSTRUCTION_RENAME; + item->_direction = SyncFileItem::Down; + item->_renameTarget = path._target; + item->_file = adjustedOriginalPath; + item->_originalFile = originalPath; + path._original = originalPath; + path._local = adjustedOriginalPath; + qCInfo(lcDisco) << "Rename detected (down) " << item->_file << " -> " << item->_renameTarget; + }; + + if (wasDeletedOnServer) { + postProcessRename(path); + done = true; } else { - item->_instruction = CSYNC_INSTRUCTION_SYNC; + // we need to make a request to the server to know that the original file is deleted on the server + _pendingAsyncJobs++; + auto job = new RequestEtagJob(_discoveryData->_account, originalPath, this); + connect(job, &RequestEtagJob::finishedWithResult, this, [=](const Result &etag) mutable { + _pendingAsyncJobs--; + QTimer::singleShot(0, _discoveryData, &DiscoveryPhase::scheduleMoreJobs); + if (etag.errorCode() != 404 || + // Somehow another item claimed this original path, consider as if it existed + _discoveryData->_renamedItems.contains(originalPath)) { + // If the file exist or if there is another error, consider it is a new file. + postProcessServerNew(); + return; + } + + // The file do not exist, it is a rename + + // In case the deleted item was discovered in parallel + _discoveryData->findAndCancelDeletedJob(originalPath); + + postProcessRename(path); + processFileFinalize(item, path, item->isDirectory(), item->_instruction == CSYNC_INSTRUCTION_RENAME ? NormalQuery : ParentDontExist, _queryServer); + }); + job->start(); + done = true; // Ideally, if the origin still exist on the server, we should continue searching... but that'd be difficult + async = true; } - } else if (dbEntry._remotePerm != serverEntry.remotePerm || dbEntry._fileId != serverEntry.fileId) { - item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - item->_direction = SyncFileItem::Down; - } else { - processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, ParentNotChanged); + }; + if (!_discoveryData->_statedb->getFileRecordsByFileId(serverEntry.fileId, renameCandidateProcessing)) { + dbError(); return; } + if (async) { + return; // We went async + } + if (item->_instruction == CSYNC_INSTRUCTION_NEW) { + postProcessServerNew(); + return; + } processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer); }