From: Olivier Goffart Date: Wed, 11 Jul 2018 15:45:47 +0000 (+0200) Subject: New discovery algorithm: Local rename X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~558 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=5a57a36729b26171b591aa37ff5c513ed1d1c090;p=nextcloud-desktop.git New discovery algorithm: Local rename --- diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp index c144cee91..f440dcdc7 100644 --- a/src/csync/csync_update.cpp +++ b/src/csync/csync_update.cpp @@ -298,47 +298,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr f } else { /* check if it's a file and has been renamed */ if (ctx->current == LOCAL_REPLICA) { - qCInfo(lcUpdate, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode); - - OCC::SyncJournalFileRecord base; - if(!ctx->statedb->getFileRecordByInode(fs->inode, &base)) { - ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; - return -1; - } - - // Default to NEW unless we're sure it's a rename. - fs->instruction = CSYNC_INSTRUCTION_NEW; - - bool isRename = - base.isValid() && base._type == fs->type - && ((base._modtime == fs->modtime && base._fileSize == fs->size) || fs->type == ItemTypeDirectory) -#ifdef NO_RENAME_EXTENSION - && _csync_sameextension(base._path, fs->path) -#endif - ; - - - // Verify the checksum where possible - if (isRename && !base._checksumHeader.isEmpty() && ctx->callbacks.checksum_hook - && fs->type == ItemTypeFile) { - fs->checksumHeader = ctx->callbacks.checksum_hook( - _rel_to_abs(ctx, fs->path), base._checksumHeader, - ctx->callbacks.checksum_userdata); - if (!fs->checksumHeader.isEmpty()) { - qCInfo(lcUpdate, "checking checksum of potential rename %s %s <-> %s", fs->path.constData(), fs->checksumHeader.constData(), base._checksumHeader.constData()); - isRename = fs->checksumHeader == base._checksumHeader; - } - } - - if (isRename) { - qCInfo(lcUpdate, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode); - /* inode found so the file has been renamed */ - fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; - if (fs->type == ItemTypeDirectory) { - csync_rename_record(ctx, base._path, fs->path); - } - } - goto out; + /* ... PORTED */ } else { /*... PORTED ... */ } diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index dcb2bd900..34a2dc423 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -320,6 +320,21 @@ void ProcessDirectoryJob::processFile(PathTuple path, auto item = SyncFileItem::fromSyncJournalFileRecord(dbEntry); item->_file = path._target; + item->_originalFile = path._original; + + auto computeLocalChecksum = [&](const QByteArray &type, const QString &path) { + if (!type.isEmpty()) { + // TODO: compute async? + QByteArray checksum = ComputeChecksum::computeNow(_discoveryData->_localDir + path, type); + if (!checksum.isEmpty()) { + item->_checksumHeader = makeChecksumHeader(type, checksum); + return true; + } + } + return false; + }; + + auto recurseQueryServer = _queryServer; if (_queryServer == NormalQuery && serverEntry.isValid()) { item->_checksumHeader = serverEntry.checksumHeader; @@ -531,7 +546,7 @@ void ProcessDirectoryJob::processFile(PathTuple path, } } item->_direction = item->_instruction == CSYNC_INSTRUCTION_CONFLICT ? SyncFileItem::None : SyncFileItem::Down; - } else if (!dbEntry.isValid()) { + } else if (!dbEntry.isValid()) { // New local file item->_instruction = CSYNC_INSTRUCTION_NEW; item->_direction = SyncFileItem::Up; // TODO! rename; @@ -540,6 +555,56 @@ void ProcessDirectoryJob::processFile(PathTuple path, item->_modtime = localEntry.modtime; item->_type = localEntry.isDirectory ? ItemTypeDirectory : ItemTypeFile; _childModified = true; + + // Check if it is a rename + OCC::SyncJournalFileRecord base; + if (!_discoveryData->_statedb->getFileRecordByInode(localEntry.inode, &base)) { + qFatal("TODO: handle DB Errors"); + } + bool isRename = base.isValid() && base._type == item->_type + && ((base._modtime == localEntry.modtime && base._fileSize == localEntry.size) || item->_type == ItemTypeDirectory); + + if (isRename) { + // The old file must have been deleted. + isRename = !QFile::exists(_discoveryData->_localDir + base._path); + } + + // Verify the checksum where possible + if (isRename && !base._checksumHeader.isEmpty() && item->_type == ItemTypeFile) { + if (computeLocalChecksum(parseChecksumHeaderType(base._checksumHeader), path._original)) { + qCInfo(lcDisco) << "checking checksum of potential rename " << path._original << item->_checksumHeader << base._checksumHeader; + isRename = item->_checksumHeader == base._checksumHeader; + } + } + if (isRename) { + auto originalPath = QString::fromUtf8(base._path); + auto it = _discoveryData->_deletedItem.find(originalPath); + if (it != _discoveryData->_deletedItem.end()) { + if ((*it)->_instruction != CSYNC_INSTRUCTION_REMOVE) + isRename = false; + else + (*it)->_instruction = CSYNC_INSTRUCTION_NONE; + } + if (_discoveryData->_renamedItems.contains(originalPath)) + isRename = false; + if (isRename) { + delete _discoveryData->_queuedDeletedDirectories.take(originalPath); + _discoveryData->_renamedItems.insert(originalPath); + + item->_modtime = base._modtime; + item->_inode = base._inode; + item->_instruction = CSYNC_INSTRUCTION_RENAME; + item->_direction = SyncFileItem::Up; + item->_renameTarget = path._target; + item->_file = originalPath; + item->_originalFile = originalPath; + item->_fileId = base._fileId; + item->_etag = base._etag; + path._original = originalPath; + path._server = originalPath; + qCInfo(lcDisco) << "Rename detected (up) " << item->_file << " -> " << item->_renameTarget; + } + } } else { item->_instruction = CSYNC_INSTRUCTION_SYNC; item->_direction = SyncFileItem::Up; @@ -554,17 +619,9 @@ void ProcessDirectoryJob::processFile(PathTuple path, // check #4754 #4755 bool isEmlFile = path._original.endsWith(QLatin1String(".eml"), Qt::CaseInsensitive); if (isEmlFile && dbEntry._fileSize == localEntry.size && !dbEntry._checksumHeader.isEmpty()) { - QByteArray type = parseChecksumHeaderType(dbEntry._checksumHeader); - if (!type.isEmpty()) { - // TODO: compute async? - QByteArray checksum = ComputeChecksum::computeNow(_discoveryData->_localDir + path._local, type); - if (!checksum.isEmpty()) { - item->_checksumHeader = makeChecksumHeader(type, checksum); - if (item->_checksumHeader == dbEntry._checksumHeader) { - qCInfo(lcDisco) << "NOTE: Checksums are identical, file did not actually change: " << path._local; - item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - } - } + if (computeLocalChecksum(parseChecksumHeaderType(dbEntry._checksumHeader), path._local) && item->_checksumHeader == dbEntry._checksumHeader) { + qCInfo(lcDisco) << "NOTE: Checksums are identical, file did not actually change: " << path._local; + item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; } } }