[Pkg-owncloud-commits] [owncloud-client] 87/171: Propagation: Fix dir <-> file changes propagating to server #4302
Sandro Knauß
hefee-guest at moszumanska.debian.org
Wed Feb 17 09:36:52 UTC 2016
This is an automated email from the git hooks/post-receive script.
hefee-guest pushed a commit to annotated tag upstream/2.1.1+dfsg
in repository owncloud-client.
commit abf5a5ad1e4eadbeb24a999aeeab39ed4357eef9
Author: Christian Kamm <mail at ckamm.de>
Date: Wed Jan 6 10:01:22 2016 +0100
Propagation: Fix dir <-> file changes propagating to server #4302
* Ensure every time a file becomes a directory or the other way around
the item is flagged as INSTRUCTION_TYPE_CHANGE.
* Delete the badly-typed entity if necessary in the propagation jobs.
---
csync/src/csync.h | 5 ++-
csync/src/csync_reconcile.c | 8 +++-
csync/src/csync_update.c | 5 +++
csync/src/csync_util.c | 1 +
src/gui/folder.cpp | 1 +
src/gui/folderstatusmodel.cpp | 1 +
src/gui/syncrunfilelog.cpp | 3 ++
src/libsync/owncloudpropagator.cpp | 71 +++++++++++++++++++++---------------
src/libsync/progressdispatcher.cpp | 2 +
src/libsync/progressdispatcher.h | 3 +-
src/libsync/propagatedownload.cpp | 41 +++++++++++++++++++++
src/libsync/propagatedownload.h | 16 +++++++-
src/libsync/propagateremotemkdir.cpp | 27 +++++++++++++-
src/libsync/propagateremotemkdir.h | 13 ++++++-
src/libsync/propagateupload.cpp | 39 ++++++++++++++++++--
src/libsync/propagateupload.h | 16 +++++++-
src/libsync/propagatorjobs.cpp | 35 ------------------
src/libsync/propagatorjobs.h | 20 ----------
src/libsync/syncengine.cpp | 14 ++++---
19 files changed, 221 insertions(+), 100 deletions(-)
diff --git a/csync/src/csync.h b/csync/src/csync.h
index 06a4497..49cad89 100644
--- a/csync/src/csync.h
+++ b/csync/src/csync.h
@@ -134,7 +134,10 @@ enum csync_instructions_e {
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
- CSYNC_INSTRUCTION_ERROR = 0x00000100
+ CSYNC_INSTRUCTION_ERROR = 0x00000100,
+ CSYNC_INSTRUCTION_TYPE_CHANGE = 0x0000200, /* Like NEW, but deletes the old entity first (RECONCILE)
+ Used when the type of something changes from directory to file
+ or back. */
};
enum csync_ftw_type_e {
diff --git a/csync/src/csync_reconcile.c b/csync/src/csync_reconcile.c
index 8fb295f..ab25b1c 100644
--- a/csync/src/csync_reconcile.c
+++ b/csync/src/csync_reconcile.c
@@ -283,7 +283,13 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
break;
/* file on the other replica has not been modified */
case CSYNC_INSTRUCTION_NONE:
- cur->instruction = CSYNC_INSTRUCTION_SYNC;
+ if (cur->type != other->type) {
+ // If the type of the entity changed, it's like NEW, but
+ // needs to delete the other entity first.
+ cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE;
+ } else {
+ cur->instruction = CSYNC_INSTRUCTION_SYNC;
+ }
break;
case CSYNC_INSTRUCTION_IGNORE:
cur->instruction = CSYNC_INSTRUCTION_IGNORE;
diff --git a/csync/src/csync_update.c b/csync/src/csync_update.c
index d166714..bd0a4c7 100644
--- a/csync/src/csync_update.c
+++ b/csync/src/csync_update.c
@@ -301,6 +301,11 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
goto out;
}
}
+
+ // Preserve the EVAL flag later on if the type has changed.
+ if (tmp->type != fs->type)
+ st->child_modified = 1;
+
st->instruction = CSYNC_INSTRUCTION_EVAL;
goto out;
}
diff --git a/csync/src/csync_util.c b/csync/src/csync_util.c
index d9e27b7..b1746b1 100644
--- a/csync/src/csync_util.c
+++ b/csync/src/csync_util.c
@@ -55,6 +55,7 @@ static const _instr_code_struct _instr[] =
{ "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC },
{ "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
{ "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
+ { "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE },
{ NULL, CSYNC_INSTRUCTION_ERROR }
};
diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp
index 0483021..75648c3 100644
--- a/src/gui/folder.cpp
+++ b/src/gui/folder.cpp
@@ -434,6 +434,7 @@ void Folder::bubbleUpSyncResult()
if (!item->hasErrorStatus() && item->_direction == SyncFileItem::Down) {
switch (item->_instruction) {
case CSYNC_INSTRUCTION_NEW:
+ case CSYNC_INSTRUCTION_TYPE_CHANGE:
newItems++;
if (!firstItemNew)
firstItemNew = item;
diff --git a/src/gui/folderstatusmodel.cpp b/src/gui/folderstatusmodel.cpp
index fc3fc81..d45800d 100644
--- a/src/gui/folderstatusmodel.cpp
+++ b/src/gui/folderstatusmodel.cpp
@@ -980,6 +980,7 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
if (state == SyncResult::Success) {
foreach (const SyncFileItemPtr &i, f->syncResult().syncFileItemVector()) {
if (i->_isDirectory && (i->_instruction == CSYNC_INSTRUCTION_NEW
+ || i->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
|| i->_instruction == CSYNC_INSTRUCTION_REMOVE
|| i->_instruction == CSYNC_INSTRUCTION_RENAME)) {
// There is a new or a removed folder. reset all data
diff --git a/src/gui/syncrunfilelog.cpp b/src/gui/syncrunfilelog.cpp
index 607ca56..988d15d 100644
--- a/src/gui/syncrunfilelog.cpp
+++ b/src/gui/syncrunfilelog.cpp
@@ -78,6 +78,9 @@ QString SyncRunFileLog::instructionToStr( csync_instructions_e inst )
case CSYNC_INSTRUCTION_ERROR:
re = "INST_ERROR";
break;
+ case CSYNC_INSTRUCTION_TYPE_CHANGE:
+ re = "INST_TYPE_CHANGE";
+ break;
}
return re;
diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp
index 7e82e8c..db54bea 100644
--- a/src/libsync/owncloudpropagator.cpp
+++ b/src/libsync/owncloudpropagator.cpp
@@ -175,7 +175,8 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
if( httpStatusCode == 403 && _propagator->isInSharedDirectory(_item->_file )) {
if( !_item->_isDirectory ) {
SyncFileItemPtr downloadItem(new SyncFileItem(*_item));
- if (downloadItem->_instruction == CSYNC_INSTRUCTION_NEW) {
+ if (downloadItem->_instruction == CSYNC_INSTRUCTION_NEW
+ || downloadItem->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE) {
// don't try to recover pushing new files
return false;
} else if (downloadItem->_instruction == CSYNC_INSTRUCTION_SYNC) {
@@ -234,32 +235,39 @@ void PropagateItemJob::slotRestoreJobCompleted(const SyncFileItem& item )
// ================================================================================
PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItemPtr &item) {
+ bool deleteExisting = item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE;
switch(item->_instruction) {
case CSYNC_INSTRUCTION_REMOVE:
if (item->_direction == SyncFileItem::Down) return new PropagateLocalRemove(this, item);
else return new PropagateRemoteDelete(this, item);
case CSYNC_INSTRUCTION_NEW:
+ case CSYNC_INSTRUCTION_TYPE_CHANGE:
if (item->_isDirectory) {
- if (item->_direction == SyncFileItem::Down) return new PropagateLocalMkdir(this, item);
- else return new PropagateRemoteMkdir(this, item);
+ if (item->_direction == SyncFileItem::Down) {
+ auto job = new PropagateLocalMkdir(this, item);
+ job->setDeleteExistingFile(deleteExisting);
+ return job;
+ } else {
+ auto job = new PropagateRemoteMkdir(this, item);
+ job->setDeleteExisting(deleteExisting);
+ return job;
+ }
} //fall through
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_CONFLICT:
if (item->_isDirectory) {
- // Did a file turn into a directory?
- if (QFileInfo(getFilePath(item->_file)).isFile()) {
- auto job = new PropagateLocalMkdir(this, item);
- job->setDeleteExistingFile(true);
- return job;
- }
// Should we set the mtime?
return 0;
}
{
if (item->_direction != SyncFileItem::Up) {
- return new PropagateDownloadFileQNAM(this, item);
+ auto job = new PropagateDownloadFileQNAM(this, item);
+ job->setDeleteExistingFolder(deleteExisting);
+ return job;
} else {
- return new PropagateUploadFileQNAM(this, item);
+ auto job = new PropagateUploadFileQNAM(this, item);
+ job->setDeleteExisting(deleteExisting);
+ return job;
}
}
case CSYNC_INSTRUCTION_RENAME:
@@ -320,7 +328,9 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
delDirJob->increaseAffectedCount();
}
continue;
- } else if (item->_instruction == CSYNC_INSTRUCTION_NEW && item->_isDirectory) {
+ } else if (item->_isDirectory
+ && (item->_instruction == CSYNC_INSTRUCTION_NEW
+ || item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE)) {
// create a new directory within a deleted directory? That can happen if the directory
// etag was not fetched properly on the previous sync because the sync was aborted
// while uploading this directory (which is now removed). We can ignore it.
@@ -345,6 +355,22 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
if (item->_isDirectory) {
PropagateDirectory *dir = new PropagateDirectory(this, item);
dir->_firstJob.reset(createJob(item));
+
+ if (item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
+ && item->_direction == SyncFileItem::Up) {
+ // Skip all potential uploads to the new folder.
+ // Processing them now leads to problems with permissions:
+ // checkForPermissions() has already run and used the permissions
+ // of the file we're about to delete to decide whether uploading
+ // to the new dir is ok...
+ foreach(const SyncFileItemPtr &item2, items) {
+ if (item2->destination().startsWith(item->destination() + "/")) {
+ item2->_instruction = CSYNC_INSTRUCTION_NONE;
+ _anotherSyncNeeded = true;
+ }
+ }
+ }
+
if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
// We do the removal of directories at the end, because there might be moves from
// these directories that will happen later.
@@ -364,23 +390,10 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
}
directories.push(qMakePair(item->destination() + "/" , dir));
} else if (PropagateItemJob* current = createJob(item)) {
- // If the target of a job is currently a directory, we need to remove it!
- // This can happen when what used to be a directory changed to a file on the
- // server an a PropagateLocalRename or PropageDownload job wants to run.
- if (item->_direction == SyncFileItem::Down
- && QFileInfo(getFilePath(item->_file)).isDir()) {
- // The DirectoryConflict job *must* run before the file propagation job
- // and we also need to make sure other jobs that deal with the files
- // in the directory (like removes or moves, in particular of other
- // directories!) run first.
- // Making it a directory job ensures that moves run first and that the
- // (potential) directory rename happens before the file propagation.
- // Prepending all jobs to directoriesToRemove ensures that removals of
- // subdirectories happen before the directory is renamed.
- PropagateDirectory *dir = new PropagateDirectory(this, item);
- dir->_firstJob.reset(new PropagateLocalDirectoryConflict(this, item));
- dir->append(current);
- directoriesToRemove.prepend(dir);
+ if (item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE) {
+ // will delete directories, so defer execution
+ directoriesToRemove.prepend(current);
+ removedDirectory = item->_file + "/";
} else {
directories.top().second->append(current);
}
diff --git a/src/libsync/progressdispatcher.cpp b/src/libsync/progressdispatcher.cpp
index 4caf818..8f03228 100644
--- a/src/libsync/progressdispatcher.cpp
+++ b/src/libsync/progressdispatcher.cpp
@@ -27,6 +27,7 @@ QString Progress::asResultString( const SyncFileItem& item)
switch(item._instruction) {
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_NEW:
+ case CSYNC_INSTRUCTION_TYPE_CHANGE:
if (item._direction != SyncFileItem::Up) {
return QCoreApplication::translate( "progress", "Downloaded");
} else {
@@ -59,6 +60,7 @@ QString Progress::asActionString( const SyncFileItem &item )
case CSYNC_INSTRUCTION_CONFLICT:
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_NEW:
+ case CSYNC_INSTRUCTION_TYPE_CHANGE:
if (item._direction != SyncFileItem::Up)
return QCoreApplication::translate( "progress", "downloading");
else
diff --git a/src/libsync/progressdispatcher.h b/src/libsync/progressdispatcher.h
index 0efcee7..a89e0fd 100644
--- a/src/libsync/progressdispatcher.h
+++ b/src/libsync/progressdispatcher.h
@@ -79,7 +79,8 @@ public:
return ! item._isDirectory && (
item._instruction == CSYNC_INSTRUCTION_CONFLICT
|| item._instruction == CSYNC_INSTRUCTION_SYNC
- || item._instruction == CSYNC_INSTRUCTION_NEW);
+ || item._instruction == CSYNC_INSTRUCTION_NEW
+ || item._instruction == CSYNC_INSTRUCTION_TYPE_CHANGE);
}
/**
diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp
index f19dce9..2b6e014 100644
--- a/src/libsync/propagatedownload.cpp
+++ b/src/libsync/propagatedownload.cpp
@@ -310,6 +310,15 @@ void PropagateDownloadFileQNAM::start()
qDebug() << Q_FUNC_INFO << _item->_file << _propagator->_activeJobs;
+ if (_deleteExisting) {
+ deleteExistingFolder();
+
+ // check for error with deletion
+ if (_state == Finished) {
+ return;
+ }
+ }
+
// do a klaas' case clash check.
if( _propagator->localFileNameClash(_item->_file) ) {
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
@@ -415,6 +424,11 @@ qint64 PropagateDownloadFileQNAM::committedDiskSpace() const
return 0;
}
+void PropagateDownloadFileQNAM::setDeleteExistingFolder(bool enabled)
+{
+ _deleteExisting = enabled;
+}
+
const char owncloudCustomSoftErrorStringC[] = "owncloud-custom-soft-error-string";
void PropagateDownloadFileQNAM::slotGetFinished()
{
@@ -551,6 +565,33 @@ void PropagateDownloadFileQNAM::slotChecksumFail( const QString& errMsg )
done(SyncFileItem::SoftError, errMsg ); // tr("The file downloaded with a broken checksum, will be redownloaded."));
}
+void PropagateDownloadFileQNAM::deleteExistingFolder()
+{
+ QString existingDir = _propagator->getFilePath(_item->_file);
+ if (!QFileInfo(existingDir).isDir()) {
+ return;
+ }
+
+ // Delete the directory if it is empty!
+ QDir dir(existingDir);
+ if (dir.entryList(QDir::NoDotAndDotDot|QDir::AllEntries).count() == 0) {
+ if (dir.rmdir(existingDir)) {
+ return;
+ }
+ // on error, just try to move it away...
+ }
+
+ QString conflictDir = FileSystem::makeConflictFileName(
+ existingDir, Utility::qDateTimeFromTime_t(_item->_modtime));
+
+ _propagator->addTouchedFile(existingDir);
+ _propagator->addTouchedFile(conflictDir);
+ QString renameError;
+ if (!FileSystem::rename(existingDir, conflictDir, &renameError)) {
+ done(SyncFileItem::NormalError, renameError);
+ }
+}
+
namespace { // Anonymous namespace for the recall feature
static QString makeRecallFileName(const QString &fn)
{
diff --git a/src/libsync/propagatedownload.h b/src/libsync/propagatedownload.h
index 32e05db..8ba11f1 100644
--- a/src/libsync/propagatedownload.h
+++ b/src/libsync/propagatedownload.h
@@ -110,10 +110,21 @@ class PropagateDownloadFileQNAM : public PropagateItemJob {
Q_OBJECT
public:
PropagateDownloadFileQNAM(OwncloudPropagator* propagator,const SyncFileItemPtr& item)
- : PropagateItemJob(propagator, item), _resumeStart(0), _downloadProgress(0) {}
+ : PropagateItemJob(propagator, item), _resumeStart(0), _downloadProgress(0), _deleteExisting(false) {}
void start() Q_DECL_OVERRIDE;
qint64 committedDiskSpace() const Q_DECL_OVERRIDE;
+ /**
+ * Whether an existing folder with the same name may be deleted before
+ * the download.
+ *
+ * If it's a non-empty folder, it'll be renamed to a conflict-style name
+ * to preserve any non-synced content that may be inside.
+ *
+ * Default: false.
+ */
+ void setDeleteExistingFolder(bool enabled);
+
private slots:
void slotGetFinished();
void abort() Q_DECL_OVERRIDE;
@@ -122,10 +133,13 @@ private slots:
void slotChecksumFail( const QString& errMsg );
private:
+ void deleteExistingFolder();
+
quint64 _resumeStart;
qint64 _downloadProgress;
QPointer<GETFileJob> _job;
QFile _tmpFile;
+ bool _deleteExisting;
};
}
diff --git a/src/libsync/propagateremotemkdir.cpp b/src/libsync/propagateremotemkdir.cpp
index 8498491..0c91bb2 100644
--- a/src/libsync/propagateremotemkdir.cpp
+++ b/src/libsync/propagateremotemkdir.cpp
@@ -16,6 +16,7 @@
#include "owncloudpropagator_p.h"
#include "account.h"
#include "syncjournalfilerecord.h"
+#include "propagateremotedelete.h"
#include <QFile>
namespace OCC {
@@ -27,11 +28,30 @@ void PropagateRemoteMkdir::start()
qDebug() << Q_FUNC_INFO << _item->_file;
+ _propagator->_activeJobs++;
+
+ if (!_deleteExisting) {
+ return slotStartMkcolJob();
+ }
+
+ _job = new DeleteJob(_propagator->account(),
+ _propagator->_remoteFolder + _item->_file,
+ this);
+ connect(_job, SIGNAL(finishedSignal()), SLOT(slotStartMkcolJob()));
+ _job->start();
+}
+
+void PropagateRemoteMkdir::slotStartMkcolJob()
+{
+ if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
+ return;
+
+ qDebug() << Q_FUNC_INFO << _item->_file;
+
_job = new MkColJob(_propagator->account(),
_propagator->_remoteFolder + _item->_file,
this);
connect(_job, SIGNAL(finished(QNetworkReply::NetworkError)), this, SLOT(slotMkcolJobFinished()));
- _propagator->_activeJobs++;
_job->start();
}
@@ -41,6 +61,11 @@ void PropagateRemoteMkdir::abort()
_job->reply()->abort();
}
+void PropagateRemoteMkdir::setDeleteExisting(bool enabled)
+{
+ _deleteExisting = enabled;
+}
+
void PropagateRemoteMkdir::slotMkcolJobFinished()
{
_propagator->_activeJobs--;
diff --git a/src/libsync/propagateremotemkdir.h b/src/libsync/propagateremotemkdir.h
index 9dcbb73..4df6bb5 100644
--- a/src/libsync/propagateremotemkdir.h
+++ b/src/libsync/propagateremotemkdir.h
@@ -25,13 +25,24 @@ namespace OCC {
class PropagateRemoteMkdir : public PropagateItemJob {
Q_OBJECT
QPointer<AbstractNetworkJob> _job;
+ bool _deleteExisting;
friend class PropagateDirectory; // So it can access the _item;
public:
PropagateRemoteMkdir (OwncloudPropagator* propagator,const SyncFileItemPtr& item)
- : PropagateItemJob(propagator, item) {}
+ : PropagateItemJob(propagator, item), _deleteExisting(false) {}
void start() Q_DECL_OVERRIDE;
void abort() Q_DECL_OVERRIDE;
+
+ /**
+ * Whether an existing entity with the same name may be deleted before
+ * creating the directory.
+ *
+ * Default: false.
+ */
+ void setDeleteExisting(bool enabled);
+
private slots:
+ void slotStartMkcolJob();
void slotMkcolJobFinished();
void propfindResult(const QVariantMap &);
void propfindError();
diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp
index 2d5e40e..e468f87 100644
--- a/src/libsync/propagateupload.cpp
+++ b/src/libsync/propagateupload.cpp
@@ -24,6 +24,7 @@
#include "propagatorjobs.h"
#include "checksums.h"
#include "syncengine.h"
+#include "propagateremotedelete.h"
#include <json.h>
#include <QNetworkAccessManager>
@@ -208,6 +209,29 @@ void PropagateUploadFileQNAM::start()
}
}
+ _propagator->_activeJobs++;
+
+ if (!_deleteExisting) {
+ return slotComputeContentChecksum();
+ }
+
+ auto job = new DeleteJob(_propagator->account(),
+ _propagator->_remoteFolder + _item->_file,
+ this);
+ _jobs.append(job);
+ connect(job, SIGNAL(finishedSignal()), SLOT(slotComputeContentChecksum()));
+ connect(job, SIGNAL(destroyed(QObject*)), SLOT(slotJobDestroyed(QObject*)));
+ job->start();
+}
+
+void PropagateUploadFileQNAM::slotComputeContentChecksum()
+{
+ if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
+ return;
+ }
+
+ _propagator->_activeJobs--; // from start
+
const QString filePath = _propagator->getFilePath(_item->_file);
// remember the modtime before checksumming to be able to detect a file
@@ -239,6 +263,11 @@ void PropagateUploadFileQNAM::start()
computeChecksum->start(filePath);
}
+void PropagateUploadFileQNAM::setDeleteExisting(bool enabled)
+{
+ _deleteExisting = enabled;
+}
+
void PropagateUploadFileQNAM::slotComputeTransmissionChecksum(const QByteArray& contentChecksumType, const QByteArray& contentChecksum)
{
_item->_contentChecksum = contentChecksum;
@@ -491,8 +520,10 @@ void PropagateUploadFileQNAM::startNextChunk()
headers["OC-Tag"] = ".sys.admin#recall#";
}
- if (!_item->_etag.isEmpty() && _item->_etag != "empty_etag" &&
- _item->_instruction != CSYNC_INSTRUCTION_NEW // On new files never send a If-Match
+ if (!_item->_etag.isEmpty() && _item->_etag != "empty_etag"
+ && _item->_instruction != CSYNC_INSTRUCTION_NEW // On new files never send a If-Match
+ && _item->_instruction != CSYNC_INSTRUCTION_TYPE_CHANGE
+ && !_deleteExisting
) {
// We add quotes because the owncloud server always adds quotes around the etag, and
// csync_owncloud.c's owncloud_file_id always strips the quotes.
@@ -710,7 +741,9 @@ void PropagateUploadFileQNAM::slotPutFinished()
auto currentChunk = job->_chunk;
foreach (auto *job, _jobs) {
// Take the minimum finished one
- currentChunk = qMin(currentChunk, job->_chunk - 1);
+ if (auto putJob = qobject_cast<PUTFileJob*>(job)) {
+ currentChunk = qMin(currentChunk, putJob->_chunk - 1);
+ }
}
pi._chunk = (currentChunk + _startChunk + 1) % _chunkCount ; // next chunk to start with
pi._transferid = _transferId;
diff --git a/src/libsync/propagateupload.h b/src/libsync/propagateupload.h
index 1b4bc74..e438357 100644
--- a/src/libsync/propagateupload.h
+++ b/src/libsync/propagateupload.h
@@ -177,7 +177,7 @@ private:
int _chunkCount; /// Total number of chunks for this file
int _transferId; /// transfer id (part of the url)
QElapsedTimer _duration;
- QVector<PUTFileJob*> _jobs; /// network jobs that are currently in transit
+ QVector<AbstractNetworkJob*> _jobs; /// network jobs that are currently in transit
bool _finished; // Tells that all the jobs have been finished
// measure the performance of checksum calc and upload
@@ -186,10 +186,21 @@ private:
QByteArray _transmissionChecksum;
QByteArray _transmissionChecksumType;
+ bool _deleteExisting;
+
public:
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItemPtr& item)
- : PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false) {}
+ : PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false), _deleteExisting(false) {}
void start() Q_DECL_OVERRIDE;
+
+ /**
+ * Whether an existing entity with the same name may be deleted before
+ * the upload.
+ *
+ * Default: false.
+ */
+ void setDeleteExisting(bool enabled);
+
private slots:
void slotPutFinished();
void slotPollFinished();
@@ -200,6 +211,7 @@ private slots:
void slotJobDestroyed(QObject *job);
void slotStartUpload(const QByteArray& transmissionChecksumType, const QByteArray& transmissionChecksum);
void slotComputeTransmissionChecksum(const QByteArray& contentChecksumType, const QByteArray& contentChecksum);
+ void slotComputeContentChecksum();
private:
void startPollJob(const QString& path);
diff --git a/src/libsync/propagatorjobs.cpp b/src/libsync/propagatorjobs.cpp
index 1e431bd..a133b67 100644
--- a/src/libsync/propagatorjobs.cpp
+++ b/src/libsync/propagatorjobs.cpp
@@ -244,39 +244,4 @@ void PropagateLocalRename::start()
done(SyncFileItem::Success);
}
-void PropagateLocalDirectoryConflict::start()
-{
- if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
- return;
-
- QString existingDir = _propagator->getFilePath(_item->_file);
- if (!QFileInfo(existingDir).isDir()) {
- done(SyncFileItem::Success);
- return;
- }
-
- // Delete the directory if it is empty!
- QDir dir(existingDir);
- if (dir.entryList(QDir::NoDotAndDotDot|QDir::AllEntries).count() == 0) {
- if (dir.rmdir(existingDir)) {
- done(SyncFileItem::Success);
- return;
- }
- // on error, just try to move it away...
- }
-
- QString conflictDir = FileSystem::makeConflictFileName(
- existingDir, Utility::qDateTimeFromTime_t(_item->_modtime));
-
- _propagator->addTouchedFile(existingDir);
- _propagator->addTouchedFile(conflictDir);
- QString renameError;
- if (!FileSystem::rename(existingDir, conflictDir, &renameError)) {
- done(SyncFileItem::NormalError, renameError);
- return;
- }
-
- done(SyncFileItem::Success);
-}
-
}
diff --git a/src/libsync/propagatorjobs.h b/src/libsync/propagatorjobs.h
index 5a81d30..c3898db 100644
--- a/src/libsync/propagatorjobs.h
+++ b/src/libsync/propagatorjobs.h
@@ -82,24 +82,4 @@ public:
JobParallelism parallelism() Q_DECL_OVERRIDE { return WaitForFinishedInParentDirectory; }
};
-/**
- * Moves away a local directory when it should become a file.
- *
- * Example: Locally there's directory foo/ with three files in it,
- * one of them ignored, while the server has a file foo.
- * In this case, foo/ fill be moved to foo-conflict.../ and the
- * file will be downloaded to foo.
- *
- * If the directory is empty, it will be removed instead.
- *
- * @ingroup libsync
- */
-class PropagateLocalDirectoryConflict : public PropagateItemJob {
- Q_OBJECT
-public:
- PropagateLocalDirectoryConflict (OwncloudPropagator* propagator, const SyncFileItemPtr& item) : PropagateItemJob(propagator, item) {}
- void start() Q_DECL_OVERRIDE;
- JobParallelism parallelism() Q_DECL_OVERRIDE { return WaitForFinishedInParentDirectory; }
-};
-
}
diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp
index 38aff9f..6be3e93 100644
--- a/src/libsync/syncengine.cpp
+++ b/src/libsync/syncengine.cpp
@@ -444,7 +444,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
item->_errorString = tr("Filename encoding is not valid");
}
- item->_isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
+ bool isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
if (file->etag && file->etag[0]) {
item->_etag = file->etag;
@@ -474,7 +474,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
int re = 0;
switch(file->instruction) {
case CSYNC_INSTRUCTION_NONE: {
- if (remote && item->_should_update_metadata && !item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NONE) {
+ if (remote && item->_should_update_metadata && !isDirectory && item->_instruction == CSYNC_INSTRUCTION_NONE) {
// Update the database now already: New remote fileid or Etag or RemotePerm
// Or for files that were detected as "resolved conflict".
// Or a local inode/mtime change (see localMetadataUpdate below)
@@ -509,17 +509,18 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
_syncItemMap.remove(key);
}
// Any files that are instruction NONE?
- if (!item->_isDirectory && file->other.instruction == CSYNC_INSTRUCTION_NONE) {
+ if (!isDirectory && file->other.instruction == CSYNC_INSTRUCTION_NONE) {
_hasNoneFiles = true;
}
// We want to still update etags of directories, other NONE
// items can be ignored.
- bool directoryEtagUpdate = item->_isDirectory && file->should_update_metadata;
+ bool directoryEtagUpdate = isDirectory && file->should_update_metadata;
bool localMetadataUpdate = !remote && file->should_update_metadata;
if (!directoryEtagUpdate) {
if (localMetadataUpdate) {
// Hack, we want a local metadata update to happen, but only if the
// remote tree doesn't ask us to do some kind of propagation.
+ item->_isDirectory = isDirectory;
_syncItemMap.insert(key, item);
}
return re;
@@ -529,7 +530,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
case CSYNC_INSTRUCTION_RENAME:
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
item->_renameTarget = renameTarget;
- if (item->_isDirectory)
+ if (isDirectory)
_renamedFolders.insert(item->_file, item->_renameTarget);
break;
case CSYNC_INSTRUCTION_REMOVE:
@@ -543,6 +544,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
break;
case CSYNC_INSTRUCTION_EVAL:
case CSYNC_INSTRUCTION_NEW:
+ case CSYNC_INSTRUCTION_TYPE_CHANGE:
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_STAT_ERROR:
default:
@@ -556,6 +558,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
}
item->_direction = dir;
+ item->_isDirectory = isDirectory;
if (instruction != CSYNC_INSTRUCTION_NONE) {
// check for blacklisting of this item.
// if the item is on blacklist, the instruction was set to ERROR
@@ -1010,6 +1013,7 @@ void SyncEngine::checkForPermission()
}
switch((*it)->_instruction) {
+ case CSYNC_INSTRUCTION_TYPE_CHANGE:
case CSYNC_INSTRUCTION_NEW: {
int slashPos = (*it)->_file.lastIndexOf('/');
QString parentDir = slashPos <= 0 ? "" : (*it)->_file.mid(0, slashPos);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-client.git
More information about the Pkg-owncloud-commits
mailing list