[Pkg-owncloud-commits] [owncloud-client] 61/171: Propagator: Deal with directories becoming files #4302

Sandro Knauß hefee-guest at moszumanska.debian.org
Wed Feb 17 09:36:49 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 d4edab02b0ce9734fa946a73d63282b75a443989
Author: Christian Kamm <mail at ckamm.de>
Date:   Tue Dec 22 13:02:02 2015 +0100

    Propagator: Deal with directories becoming files #4302
    
    Note, in particular the revised order of directory deletion jobs.
---
 src/libsync/filesystem.cpp         | 21 +++++++++++++++++++++
 src/libsync/filesystem.h           |  5 +++++
 src/libsync/owncloudpropagator.cpp | 23 +++++++++++++++++++++--
 src/libsync/owncloudpropagator.h   | 12 ++++++++----
 src/libsync/propagatedownload.cpp  | 24 +-----------------------
 src/libsync/propagatorjobs.cpp     | 35 +++++++++++++++++++++++++++++++++++
 src/libsync/propagatorjobs.h       | 19 +++++++++++++++++++
 7 files changed, 110 insertions(+), 29 deletions(-)

diff --git a/src/libsync/filesystem.cpp b/src/libsync/filesystem.cpp
index 5699979..15bb001 100644
--- a/src/libsync/filesystem.cpp
+++ b/src/libsync/filesystem.cpp
@@ -543,4 +543,25 @@ QByteArray FileSystem::calcAdler32( const QString& filename )
 }
 #endif
 
+QString FileSystem::makeConflictFileName(const QString &fn, const QDateTime &dt)
+{
+    QString conflictFileName(fn);
+    // Add _conflict-XXXX  before the extension.
+    int dotLocation = conflictFileName.lastIndexOf('.');
+    // If no extension, add it at the end  (take care of cases like foo/.hidden or foo.bar/file)
+    if (dotLocation <= conflictFileName.lastIndexOf('/') + 1) {
+        dotLocation = conflictFileName.size();
+    }
+    QString timeString = dt.toString("yyyyMMdd-hhmmss");
+
+    // Additional marker
+    QByteArray conflictFileUserName = qgetenv("CSYNC_CONFLICT_FILE_USERNAME");
+    if (conflictFileUserName.isEmpty())
+        conflictFileName.insert(dotLocation, "_conflict-" + timeString);
+    else
+        conflictFileName.insert(dotLocation, "_conflict_" + QString::fromUtf8(conflictFileUserName)  + "-" + timeString);
+
+    return conflictFileName;
+}
+
 } // namespace OCC
diff --git a/src/libsync/filesystem.h b/src/libsync/filesystem.h
index 21e6975..877687a 100644
--- a/src/libsync/filesystem.h
+++ b/src/libsync/filesystem.h
@@ -169,6 +169,11 @@ QByteArray OWNCLOUDSYNC_EXPORT calcSha1( const QString& fileName );
 QByteArray OWNCLOUDSYNC_EXPORT calcAdler32( const QString& fileName );
 #endif
 
+/**
+ * Returns a file name based on \a fn that's suitable for a conflict.
+ */
+QString OWNCLOUDSYNC_EXPORT makeConflictFileName(const QString &fn, const QDateTime &dt);
+
 }
 
 /** @} */
diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp
index 9f86f86..f016601 100644
--- a/src/libsync/owncloudpropagator.cpp
+++ b/src/libsync/owncloudpropagator.cpp
@@ -346,7 +346,7 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
             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.
-                directoriesToRemove.append(dir);
+                directoriesToRemove.prepend(dir);
                 removedDirectory = item->_file + "/";
 
                 // We should not update the etag of parent directories of the removed directory
@@ -362,7 +362,26 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
             }
             directories.push(qMakePair(item->destination() + "/" , dir));
         } else if (PropagateItemJob* current = createJob(item)) {
-            directories.top().second->append(current);
+            // 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);
+            } else {
+                directories.top().second->append(current);
+            }
         }
     }
 
diff --git a/src/libsync/owncloudpropagator.h b/src/libsync/owncloudpropagator.h
index 15189bb..718250d 100644
--- a/src/libsync/owncloudpropagator.h
+++ b/src/libsync/owncloudpropagator.h
@@ -73,12 +73,16 @@ public:
 
         /** Jobs can be run in parallel to this job */
         FullParallelism,
-        /** This job does not support parallelism, and no other job shall
-            be started until this one has finished */
+
+        /** No other job shall be started until this one has finished.
+            So this job is guaranteed to finish before any jobs below it
+            are executed. */
         WaitForFinished,
 
-        /** This job supports parallelism with other jobs in the same directory, but it should
-             not be parallelized with jobs in other directories  (typically a move operation) */
+        /** A job with this parallelism will allow later jobs to start and
+            run in parallel as long as they aren't PropagateDirectory jobs.
+            When the first directory job is encountered, no further jobs
+            will be started until this one is finished. */
         WaitForFinishedInParentDirectory
     };
 
diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp
index 305f897..689caa2 100644
--- a/src/libsync/propagatedownload.cpp
+++ b/src/libsync/propagatedownload.cpp
@@ -551,28 +551,6 @@ void PropagateDownloadFileQNAM::slotChecksumFail( const QString& errMsg )
     done(SyncFileItem::SoftError, errMsg ); // tr("The file downloaded with a broken checksum, will be redownloaded."));
 }
 
-QString makeConflictFileName(const QString &fn, const QDateTime &dt)
-{
-    QString conflictFileName(fn);
-    // Add _conflict-XXXX  before the extension.
-    int dotLocation = conflictFileName.lastIndexOf('.');
-    // If no extension, add it at the end  (take care of cases like foo/.hidden or foo.bar/file)
-    if (dotLocation <= conflictFileName.lastIndexOf('/') + 1) {
-        dotLocation = conflictFileName.size();
-    }
-    QString timeString = dt.toString("yyyyMMdd-hhmmss");
-
-    // Additional marker
-    QByteArray conflictFileUserName = qgetenv("CSYNC_CONFLICT_FILE_USERNAME");
-    if (conflictFileUserName.isEmpty())
-        conflictFileName.insert(dotLocation, "_conflict-" + timeString);
-    else
-        conflictFileName.insert(dotLocation, "_conflict_" + QString::fromUtf8(conflictFileUserName)  + "-" + timeString);
-
-    return conflictFileName;
-}
-
-
 namespace { // Anonymous namespace for the recall feature
 static QString makeRecallFileName(const QString &fn)
 {
@@ -636,7 +614,7 @@ void PropagateDownloadFileQNAM::downloadFinished()
             && !FileSystem::fileEquals(fn, _tmpFile.fileName());
     if (isConflict) {
         QString renameError;
-        QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item->_modtime));
+        QString conflictFileName = FileSystem::makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item->_modtime));
         if (!FileSystem::rename(fn, conflictFileName, &renameError)) {
             //If the rename fails, don't replace it.
             done(SyncFileItem::SoftError, renameError);
diff --git a/src/libsync/propagatorjobs.cpp b/src/libsync/propagatorjobs.cpp
index 30914ed..2475461 100644
--- a/src/libsync/propagatorjobs.cpp
+++ b/src/libsync/propagatorjobs.cpp
@@ -256,4 +256,39 @@ 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 2b3b9a4..5a81d30 100644
--- a/src/libsync/propagatorjobs.h
+++ b/src/libsync/propagatorjobs.h
@@ -82,5 +82,24 @@ 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; }
+};
 
 }

-- 
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