mirror of
https://github.com/nextcloud/desktop.git
synced 2024-12-21 05:13:04 +03:00
ee08b3759d
(cherry picked from commit bacf6166c1
)
183 lines
6.3 KiB
C++
183 lines
6.3 KiB
C++
/*
|
|
* Copyright (C) by Olivier Goffart <ogoffart@owncloud.com>
|
|
* Copyright (C) by Klaas Freitag <freitag@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 "propagatorjobs.h"
|
|
#include "owncloudpropagator_p.h"
|
|
|
|
#include "utility.h"
|
|
#include "syncjournaldb.h"
|
|
#include "syncjournalfilerecord.h"
|
|
#include "filesystem.h"
|
|
#include <qfile.h>
|
|
#include <qdir.h>
|
|
#include <qdiriterator.h>
|
|
#include <qtemporaryfile.h>
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
|
#include <qabstractfileengine.h>
|
|
#else
|
|
#include <qsavefile.h>
|
|
#endif
|
|
#include <QDebug>
|
|
#include <QDateTime>
|
|
#include <qstack.h>
|
|
#include <QCoreApplication>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
namespace OCC {
|
|
|
|
// Code copied from Qt5's QDir::removeRecursively
|
|
// (and modified to report the error)
|
|
static bool removeRecursively(const QString &path, QString &error)
|
|
{
|
|
bool success = true;
|
|
QDirIterator di(path, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
|
|
while (di.hasNext()) {
|
|
di.next();
|
|
const QFileInfo& fi = di.fileInfo();
|
|
bool ok;
|
|
// The use of isSymLink here is okay:
|
|
// we never want to go into this branch for .lnk files
|
|
if (fi.isDir() && !fi.isSymLink()) {
|
|
ok = removeRecursively(di.filePath(), error); // recursive
|
|
} else {
|
|
QFile f(di.filePath());
|
|
ok = f.remove();
|
|
if (!ok) {
|
|
error += PropagateLocalRemove::tr("Error removing '%1': %2;").
|
|
arg(QDir::toNativeSeparators(f.fileName()), f.errorString()) + " ";
|
|
qDebug() << "Error removing " << f.fileName() << ':' << f.errorString();
|
|
}
|
|
}
|
|
if (!ok)
|
|
success = false;
|
|
}
|
|
if (success) {
|
|
success = QDir().rmdir(path);
|
|
if (!success) {
|
|
error += PropagateLocalRemove::tr("Could not remove directory '%1';")
|
|
.arg(QDir::toNativeSeparators(path)) + " ";
|
|
qDebug() << "Error removing directory" << path;
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void PropagateLocalRemove::start()
|
|
{
|
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
|
return;
|
|
|
|
QString filename = _propagator->_localDir + _item->_file;
|
|
if( _propagator->localFileNameClash(_item->_file)) {
|
|
done(SyncFileItem::NormalError, tr("Could not remove %1 because of a local file name clash")
|
|
.arg(QDir::toNativeSeparators(filename)));
|
|
return;
|
|
}
|
|
|
|
if (_item->_isDirectory) {
|
|
QString error;
|
|
if (QDir(filename).exists() && !removeRecursively(filename, error)) {
|
|
done(SyncFileItem::NormalError, error);
|
|
return;
|
|
}
|
|
} else {
|
|
QFile file(filename);
|
|
if (FileSystem::fileExists(filename) && !file.remove()) {
|
|
done(SyncFileItem::NormalError, file.errorString());
|
|
return;
|
|
}
|
|
}
|
|
emit progress(*_item, 0);
|
|
_propagator->_journal->deleteFileRecord(_item->_originalFile, _item->_isDirectory);
|
|
_propagator->_journal->commit("Local remove");
|
|
done(SyncFileItem::Success);
|
|
}
|
|
|
|
void PropagateLocalMkdir::start()
|
|
{
|
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
|
return;
|
|
|
|
QDir newDir(_propagator->_localDir + _item->_file);
|
|
QString newDirStr = QDir::toNativeSeparators(newDir.path());
|
|
if( Utility::fsCasePreserving() && _propagator->localFileNameClash(_item->_file ) ) {
|
|
qDebug() << "WARN: new directory to create locally already exists!";
|
|
done( SyncFileItem::NormalError, tr("Attention, possible case sensitivity clash with %1").arg(newDirStr) );
|
|
return;
|
|
}
|
|
_propagator->addTouchedFile(newDirStr);
|
|
QDir localDir(_propagator->_localDir);
|
|
if (!localDir.mkpath(_item->_file)) {
|
|
done( SyncFileItem::NormalError, tr("could not create directory %1").arg(newDirStr) );
|
|
return;
|
|
}
|
|
done(SyncFileItem::Success);
|
|
}
|
|
|
|
void PropagateLocalRename::start()
|
|
{
|
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
|
return;
|
|
|
|
QString existingFile = _propagator->getFilePath(_item->_file);
|
|
QString targetFile = _propagator->getFilePath(_item->_renameTarget);
|
|
|
|
// if the file is a file underneath a moved dir, the _item->file is equal
|
|
// to _item->renameTarget and the file is not moved as a result.
|
|
if (_item->_file != _item->_renameTarget) {
|
|
emit progress(*_item, 0);
|
|
qDebug() << "MOVE " << existingFile << " => " << targetFile;
|
|
|
|
if (QString::compare(_item->_file, _item->_renameTarget, Qt::CaseInsensitive) != 0
|
|
&& _propagator->localFileNameClash(_item->_renameTarget)) {
|
|
// Only use localFileNameClash for the destination if we know that the source was not
|
|
// the one conflicting (renaming A.txt -> a.txt is OK)
|
|
|
|
// Fixme: the file that is the reason for the clash could be named here,
|
|
// it would have to come out the localFileNameClash function
|
|
done(SyncFileItem::NormalError, tr( "File %1 can not be renamed to %2 because of a local file name clash")
|
|
.arg(QDir::toNativeSeparators(_item->_file)).arg(QDir::toNativeSeparators(_item->_renameTarget)) );
|
|
return;
|
|
}
|
|
|
|
_propagator->addTouchedFile(existingFile);
|
|
_propagator->addTouchedFile(targetFile);
|
|
QString renameError;
|
|
if (!FileSystem::rename(existingFile, targetFile, &renameError)) {
|
|
done(SyncFileItem::NormalError, renameError);
|
|
return;
|
|
}
|
|
}
|
|
|
|
_propagator->_journal->deleteFileRecord(_item->_originalFile);
|
|
|
|
// store the rename file name in the item.
|
|
_item->_file = _item->_renameTarget;
|
|
|
|
SyncJournalFileRecord record(*_item, targetFile);
|
|
record._path = _item->_renameTarget;
|
|
|
|
if (!_item->_isDirectory) { // Directory are saved at the end
|
|
_propagator->_journal->setFileRecord(record);
|
|
}
|
|
_propagator->_journal->commit("localRename");
|
|
|
|
|
|
done(SyncFileItem::Success);
|
|
}
|
|
|
|
}
|