mirror of
https://github.com/nextcloud/desktop.git
synced 2024-10-27 23:17:13 +03:00
a1dc4069c9
We are going to change the webdav path depending on the capabilities. But the SyncEngine and csync might have been created before the capabilities are retrieved. The main raison why we gave the path to the sync engine was to pass it to csync. But the thing is that csync don't need anymore this url as everything is done by the discovery classes in libsync that use the network jobs that use the account for the urls. So csync do not need the remote URI. shortenFilename in folderstatusmodel.cpp was useless because the string is the _file of a SyncFileItem which is the relative file name, that name never starts with owncloud://. All the csync test creates the folder because csync use to check if the folder exists. But we don't need to do that anymore
230 lines
8.3 KiB
C++
230 lines
8.3 KiB
C++
/*
|
|
* Copyright (C) by Olivier Goffart <ogoffart@owncloud.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include "propagateremotemove.h"
|
|
#include "propagatorjobs.h"
|
|
#include "owncloudpropagator_p.h"
|
|
#include "account.h"
|
|
#include "syncjournalfilerecord.h"
|
|
#include "filesystem.h"
|
|
#include <QFile>
|
|
#include <QStringList>
|
|
#include <QDir>
|
|
|
|
namespace OCC {
|
|
|
|
MoveJob::MoveJob(AccountPtr account, const QString& path,
|
|
const QString &destination, QObject* parent)
|
|
: AbstractNetworkJob(account, path, parent), _destination(destination)
|
|
{ }
|
|
|
|
MoveJob::MoveJob(AccountPtr account, const QUrl& url, const QString &destination,
|
|
QMap<QByteArray, QByteArray> extraHeaders, QObject* parent)
|
|
: AbstractNetworkJob(account, QString(), parent), _destination(destination), _url(url)
|
|
, _extraHeaders(extraHeaders)
|
|
{ }
|
|
|
|
void MoveJob::start()
|
|
{
|
|
QNetworkRequest req;
|
|
req.setRawHeader("Destination", QUrl::toPercentEncoding(_destination, "/"));
|
|
for(auto it = _extraHeaders.constBegin(); it != _extraHeaders.constEnd(); ++it) {
|
|
req.setRawHeader(it.key(), it.value());
|
|
}
|
|
setReply(_url.isValid() ? davRequest("MOVE", _url, req) : davRequest("MOVE", path(), req));
|
|
setupConnections(reply());
|
|
|
|
if( reply()->error() != QNetworkReply::NoError ) {
|
|
qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString();
|
|
}
|
|
AbstractNetworkJob::start();
|
|
}
|
|
|
|
|
|
QString MoveJob::errorString()
|
|
{
|
|
if (_timedout) {
|
|
return tr("Connection timed out");
|
|
} else if (reply()->hasRawHeader("OC-ErrorString")) {
|
|
return reply()->rawHeader("OC-ErrorString");
|
|
} else {
|
|
return reply()->errorString();
|
|
}
|
|
}
|
|
|
|
bool MoveJob::finished()
|
|
{
|
|
emit finishedSignal();
|
|
return true;
|
|
}
|
|
|
|
void PropagateRemoteMove::start()
|
|
{
|
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
|
return;
|
|
|
|
qDebug() << Q_FUNC_INFO << _item->_file << _item->_renameTarget;
|
|
|
|
QString targetFile(_propagator->getFilePath(_item->_renameTarget));
|
|
|
|
if (_item->_file == _item->_renameTarget) {
|
|
// The parent has been renamed already so there is nothing more to do.
|
|
finalize();
|
|
return;
|
|
}
|
|
if (_item->_file == QLatin1String("Shared") ) {
|
|
// Before owncloud 7, there was no permissions system. At the time all the shared files were
|
|
// in a directory called "Shared" and were not supposed to be moved, otherwise bad things happened
|
|
|
|
QString versionString = _propagator->account()->serverVersion();
|
|
if (versionString.contains('.') && versionString.split('.')[0].toInt() < 7) {
|
|
QString originalFile(_propagator->getFilePath(QLatin1String("Shared")));
|
|
emit _propagator->touchedFile(originalFile);
|
|
emit _propagator->touchedFile(targetFile);
|
|
QString renameError;
|
|
if( FileSystem::rename(targetFile, originalFile, &renameError) ) {
|
|
done(SyncFileItem::NormalError, tr("This folder must not be renamed. It is renamed back to its original name."));
|
|
} else {
|
|
done(SyncFileItem::NormalError, tr("This folder must not be renamed. Please name it back to Shared."));
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
QString destination = QDir::cleanPath(_propagator->account()->url().path() + QLatin1Char('/')
|
|
+ _propagator->account()->davPath() + _propagator->_remoteFolder + _item->_renameTarget);
|
|
_job = new MoveJob(_propagator->account(),
|
|
_propagator->_remoteFolder + _item->_file,
|
|
destination, this);
|
|
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotMoveJobFinished()));
|
|
_propagator->_activeJobList.append(this);
|
|
_job->start();
|
|
|
|
}
|
|
|
|
void PropagateRemoteMove::abort()
|
|
{
|
|
if (_job && _job->reply())
|
|
_job->reply()->abort();
|
|
}
|
|
|
|
void PropagateRemoteMove::slotMoveJobFinished()
|
|
{
|
|
_propagator->_activeJobList.removeOne(this);
|
|
|
|
Q_ASSERT(_job);
|
|
|
|
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
|
<< _job->reply()->error()
|
|
<< (_job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : _job->reply()->errorString());
|
|
|
|
QNetworkReply::NetworkError err = _job->reply()->error();
|
|
_item->_httpErrorCode = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
|
|
if (err != QNetworkReply::NoError) {
|
|
|
|
if( checkForProblemsWithShared(_item->_httpErrorCode,
|
|
tr("The file was renamed but is part of a read only share. The original file was restored."))) {
|
|
return;
|
|
}
|
|
|
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
|
&_propagator->_anotherSyncNeeded);
|
|
done(status, _job->errorString());
|
|
return;
|
|
}
|
|
|
|
_item->_requestDuration = _job->duration();
|
|
_item->_responseTimeStamp = _job->responseTimestamp();
|
|
|
|
if (_item->_httpErrorCode != 201 ) {
|
|
// Normally we expect "201 Created"
|
|
// If it is not the case, it might be because of a proxy or gateway intercepting the request, so we must
|
|
// throw an error.
|
|
done(SyncFileItem::NormalError, tr("Wrong HTTP code returned by server. Expected 201, but received \"%1 %2\".")
|
|
.arg(_item->_httpErrorCode).arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()));
|
|
return;
|
|
}
|
|
|
|
finalize();
|
|
|
|
}
|
|
|
|
void PropagateRemoteMove::finalize()
|
|
{
|
|
SyncJournalFileRecord oldRecord =
|
|
_propagator->_journal->getFileRecord(_item->_originalFile);
|
|
// if reading from db failed still continue hoping that deleteFileRecord
|
|
// reopens the db successfully.
|
|
// The db is only queried to transfer the content checksum from the old
|
|
// to the new record. It is not a problem to skip it here.
|
|
_propagator->_journal->deleteFileRecord(_item->_originalFile);
|
|
|
|
SyncJournalFileRecord record(*_item, _propagator->getFilePath(_item->_renameTarget));
|
|
record._path = _item->_renameTarget;
|
|
if (oldRecord.isValid()) {
|
|
record._contentChecksum = oldRecord._contentChecksum;
|
|
record._contentChecksumType = oldRecord._contentChecksumType;
|
|
if (record._fileSize != oldRecord._fileSize) {
|
|
qDebug() << "Warning: file sizes differ on server vs csync_journal: " << record._fileSize << oldRecord._fileSize;
|
|
record._fileSize = oldRecord._fileSize; // server might have claimed different size, we take the old one from the DB
|
|
}
|
|
}
|
|
|
|
if (!_propagator->_journal->setFileRecord(record)) {
|
|
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
|
return;
|
|
}
|
|
|
|
if (_item->_isDirectory) {
|
|
if (!adjustSelectiveSync(_propagator->_journal, _item->_file, _item->_renameTarget)) {
|
|
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
_propagator->_journal->commit("Remote Rename");
|
|
done(SyncFileItem::Success);
|
|
}
|
|
|
|
bool PropagateRemoteMove::adjustSelectiveSync(SyncJournalDb *journal, const QString &from_, const QString &to_)
|
|
{
|
|
bool ok;
|
|
// We only care about preserving the blacklist. The white list should anyway be empty.
|
|
// And the undecided list will be repopulated on the next sync, if there is anything too big.
|
|
QStringList list = journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
|
|
if (!ok)
|
|
return false;
|
|
|
|
bool changed = false;
|
|
Q_ASSERT(!from_.endsWith(QLatin1String("/")));
|
|
Q_ASSERT(!to_.endsWith(QLatin1String("/")));
|
|
QString from = from_ + QLatin1String("/");
|
|
QString to = to_ + QLatin1String("/");
|
|
|
|
for (auto it = list.begin(); it != list.end(); ++it) {
|
|
if (it->startsWith(from)) {
|
|
*it = it->replace(0, from.size(), to);
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
if (changed) {
|
|
journal->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, list);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|