From: Olivier Goffart Date: Tue, 17 Jul 2018 15:18:07 +0000 (+0200) Subject: New Disco algorithm: Type change (file to dir) X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~550 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=35e40b58ca512fe197749733543512edf2df2f68;p=nextcloud-desktop.git New Disco algorithm: Type change (file to dir) --- diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index 463e3e631..5a50992d1 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -94,7 +94,9 @@ void ProcessDirectoryJob::start() auto dh = csync_vio_local_opendir((_discoveryData->_localDir + _currentFolder._local).toUtf8()); if (!dh) { qCInfo(lcDisco) << "Error while opening directory" << (_discoveryData->_localDir + _currentFolder._local) << errno; - serverJob->abort(); + if (serverJob) { + serverJob->abort(); + } QString errorString = tr("Error while opening directory %1").arg(_discoveryData->_localDir + _currentFolder._local); if (errno == EACCES) { errorString = tr("Directory not accessible on client, permission denied"); @@ -326,9 +328,9 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, bool isDirectory, item->_errorString = tr("Stat failed."); break; case CSYNC_FILE_EXCLUDE_CONFLICT: - qFatal("TODO: conflicts"); -#if 0 + item->_errorString = tr("Conflict: Server version downloaded, local copy renamed and not uploaded."); item->_status = SyncFileItem::Conflict; +#if 0 // TODO: port this if (_propagator->account()->capabilities().uploadConflictFiles()) { // For uploaded conflict files, files with no action performed on them should // be displayed: but we mustn't overwrite the instruction if something happens @@ -337,9 +339,6 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, bool isDirectory, item->_errorString = tr("Unresolved conflict."); item->_instruction = CSYNC_INSTRUCTION_IGNORE; } - } else { - item->_errorString = tr("Conflict: Server version downloaded, local copy renamed and not uploaded."); - } #endif break; case CSYNC_FILE_EXCLUDE_CANNOT_ENCODE: // FIXME! @@ -578,6 +577,13 @@ void ProcessDirectoryJob::processFile(PathTuple path, if (item->_instruction == CSYNC_INSTRUCTION_NEW) { postProcessNew(); } + } 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; @@ -602,7 +608,8 @@ void ProcessDirectoryJob::processFile(PathTuple path, recurseQueryServer = ParentNotChanged; } } - bool serverModified = item->_instruction == CSYNC_INSTRUCTION_NEW || item->_instruction == CSYNC_INSTRUCTION_SYNC || item->_instruction == CSYNC_INSTRUCTION_RENAME; + bool serverModified = item->_instruction == CSYNC_INSTRUCTION_NEW || item->_instruction == CSYNC_INSTRUCTION_SYNC + || item->_instruction == CSYNC_INSTRUCTION_RENAME || item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE; if ((dbEntry.isValid() && dbEntry._type == ItemTypeVirtualFile) || (localEntry.isValid() && localEntry.isVirtualFile)) { // Do not download virtual files if (serverModified || dbEntry._type != ItemTypeVirtualFile) @@ -610,9 +617,12 @@ void ProcessDirectoryJob::processFile(PathTuple path, serverModified = false; item->_type = ItemTypeVirtualFile; } - _childModified |= serverModified; + if (!_dirItem || _dirItem->_direction == SyncFileItem::Up) { + _childModified |= serverModified; + } if (localEntry.isValid()) { item->_inode = localEntry.inode; + bool typeChange = dbEntry.isValid() && localEntry.isDirectory != (dbEntry._type == ItemTypeDirectory); if (localEntry.isVirtualFile) { item->_type = ItemTypeVirtualFile; if (_queryServer != ParentNotChanged && !serverEntry.isValid()) { @@ -622,7 +632,8 @@ void ProcessDirectoryJob::processFile(PathTuple path, item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; item->_direction = SyncFileItem::Down; // Does not matter } - } else if (dbEntry.isValid() && ((dbEntry._modtime == localEntry.modtime && dbEntry._fileSize == localEntry.size) || (localEntry.isDirectory && dbEntry._type == ItemTypeDirectory))) { + } else if (dbEntry.isValid() && !typeChange && ((dbEntry._modtime == localEntry.modtime && dbEntry._fileSize == localEntry.size) || (localEntry.isDirectory && dbEntry._type == ItemTypeDirectory))) { + // Local file unchanged. if (_queryServer != ParentNotChanged && !serverEntry.isValid()) { item->_instruction = CSYNC_INSTRUCTION_REMOVE; item->_direction = SyncFileItem::Down; @@ -687,6 +698,16 @@ void ProcessDirectoryJob::processFile(PathTuple path, } } item->_direction = item->_instruction == CSYNC_INSTRUCTION_CONFLICT ? SyncFileItem::None : SyncFileItem::Down; + } else if (typeChange) { + item->_instruction = CSYNC_INSTRUCTION_TYPE_CHANGE; + item->_direction = SyncFileItem::Up; + item->_checksumHeader.clear(); + item->_size = localEntry.size; + item->_modtime = localEntry.modtime; + item->_type = localEntry.isDirectory ? ItemTypeDirectory : ItemTypeFile; + if (!_dirItem || _dirItem->_direction == SyncFileItem::Down) { + _childModified = true; + } } else if (!dbEntry.isValid()) { // New local file item->_instruction = CSYNC_INSTRUCTION_NEW; item->_direction = SyncFileItem::Up; @@ -694,8 +715,9 @@ void ProcessDirectoryJob::processFile(PathTuple path, item->_size = localEntry.size; item->_modtime = localEntry.modtime; item->_type = localEntry.isDirectory ? ItemTypeDirectory : ItemTypeFile; - _childModified = true; - + if (!_dirItem || _dirItem->_direction == SyncFileItem::Down) { + _childModified = true; + } // Check if it is a rename OCC::SyncJournalFileRecord base; if (!_discoveryData->_statedb->getFileRecordByInode(localEntry.inode, &base)) { @@ -807,7 +829,9 @@ void ProcessDirectoryJob::processFile(PathTuple path, item->_modtime = localEntry.modtime; item->_previousSize = dbEntry._fileSize; item->_previousModtime = dbEntry._modtime; - _childModified = true; + if (!_dirItem || _dirItem->_direction == SyncFileItem::Down) { + _childModified = true; + } // Checksum comparison at this stage is only enabled for .eml files, // check #4754 #4755 @@ -847,12 +871,12 @@ void ProcessDirectoryJob::processFile(PathTuple path, qCInfo(lcDisco) << "Discovered" << item->_file << item->_instruction << item->_direction << item->_type; - if (item->isDirectory()) { + if (item->isDirectory() || localEntry.isDirectory || serverEntry.isDirectory) { if (item->_instruction == CSYNC_INSTRUCTION_SYNC) { item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; } auto job = new ProcessDirectoryJob(item, recurseQueryServer, - localEntry.isValid() || item->_instruction == CSYNC_INSTRUCTION_RENAME ? NormalQuery : ParentDontExist, + localEntry.isDirectory || item->_instruction == CSYNC_INSTRUCTION_RENAME ? NormalQuery : ParentDontExist, _discoveryData, this); job->_currentFolder = path; if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) { @@ -940,6 +964,13 @@ void ProcessDirectoryJob::progress() // re-create directory that has modified contents _dirItem->_instruction = CSYNC_INSTRUCTION_NEW; } + if (_childModified && _dirItem->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE) { + if (_dirItem->_direction == SyncFileItem::Up) { + _dirItem->_type = ItemTypeDirectory; + _dirItem->_direction = SyncFileItem::Down; + } + _dirItem->_instruction = CSYNC_INSTRUCTION_CONFLICT; + } if (_childIgnored && _dirItem->_instruction == CSYNC_INSTRUCTION_REMOVE) { // Do not remove a directory that has ignored files _dirItem->_instruction = CSYNC_INSTRUCTION_NONE; diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 74d1c82ca..b45a3259a 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -369,6 +369,11 @@ void SyncEngine::conflictRecordMaintenance() void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item) { + _seenFiles.insert(item->_file); + if (!item->_renameTarget.isEmpty()) { + // Yes, this records both the rename renameTarget and the original so we keep both in case of a rename + _seenFiles.insert(item->_renameTarget); + } if (item->_instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && !item->isDirectory()) { // For directories, metadata-only updates will be done after all their files are propagated. @@ -526,14 +531,6 @@ int SyncEngine::treewalkFile(csync_file_stat_t * /*file*/, csync_file_stat_t * / item->_serverHasIgnoredFiles = file->has_ignored_files; } - // record the seen files to be able to clean the journal later - _seenFiles.insert(item->_file); - if (!renameTarget.isEmpty()) { - // Yes, this records both the rename renameTarget and the original so we keep both in case of a rename - _seenFiles.insert(renameTarget); - } - - switch (file->error_status) { @@ -579,18 +576,7 @@ int SyncEngine::treewalkFile(csync_file_stat_t * /*file*/, csync_file_stat_t * / int re = 0; switch (file->instruction) { case CSYNC_INSTRUCTION_NONE: { - // Any files that are instruction NONE? - if (!isDirectory && (!other || other->instruction == CSYNC_INSTRUCTION_NONE || other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA)) { - _hasNoneFiles = true; - } - // Put none-instruction conflict files into the syncfileitem list - if (account()->capabilities().uploadConflictFiles() - && file->error_status == CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE - && item->_instruction == CSYNC_INSTRUCTION_IGNORE) { - break; - } - // No syncing or update to be done. - return re; + ... ported .... } case CSYNC_INSTRUCTION_UPDATE_METADATA: dir = SyncFileItem::None;