Propagator: Deal with files becoming directories #4302
authorChristian Kamm <mail@ckamm.de>
Tue, 22 Dec 2015 10:26:07 +0000 (11:26 +0100)
committerChristian Kamm <mail@ckamm.de>
Tue, 5 Jan 2016 09:26:41 +0000 (10:26 +0100)
This needed adjustments in reconcile, to mark the item as SYNC
as well as additions to the LocalMkdir job.

csync/src/csync_update.c
src/libsync/owncloudpropagator.cpp
src/libsync/propagatorjobs.cpp
src/libsync/propagatorjobs.h

index 44c97038e79816d09921cc3f4d8d929dba00a5ed..d1667149f8a974466ea5420c4d56ccbe05aeb060 100644 (file)
@@ -272,6 +272,11 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
                   (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
         if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) {
             st->instruction = CSYNC_INSTRUCTION_EVAL;
+
+            // Preserve the EVAL flag later on if the type has changed.
+            if (tmp->type != fs->type)
+                st->child_modified = 1;
+
             goto out;
         }
         if (ctx->current == LOCAL_REPLICA &&
index 478f5fa5be3f577d5bb44dc5f4f06aeee4bcad8d..9f86f86332b5eeea9c3fb075e7a3b2a70d1f66f5 100644 (file)
@@ -246,6 +246,12 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItemPtr &item) {
         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;
             }
index e17ab60175219110f6ad69b665c6a481ee79b05d..30914ed19a6dabe3cd23bcede1a567a815f994f1 100644 (file)
@@ -147,8 +147,29 @@ void PropagateLocalMkdir::start()
     if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
         return;
 
-    QDir newDir(_propagator->_localDir + _item->_file);
+    QDir newDir(_propagator->getFilePath(_item->_file));
     QString newDirStr = QDir::toNativeSeparators(newDir.path());
+
+    // When turning something that used to be a file into a directory
+    // we need to delete the file first.
+    QFileInfo fi(newDirStr);
+    if (_deleteExistingFile && fi.exists() && fi.isFile()) {
+#ifdef Q_OS_WIN
+        // On Windows, write only files cannot be deleted.
+        if (!fi.isWritable()) {
+            FileSystem::setFileReadOnlyWeak(newDirStr, false);
+        }
+#endif
+
+        QFile f(newDirStr);
+        if (!f.remove()) {
+            done( SyncFileItem::NormalError,
+                  tr("could not delete file %1, error: %2")
+                  .arg(newDirStr, f.errorString()));
+            return;
+        }
+    }
+
     if( Utility::fsCasePreserving() && _propagator->localFileNameClash(_item->_file ) ) {
         qDebug() << "WARN: new folder to create locally already exists!";
         done( SyncFileItem::NormalError, tr("Attention, possible case sensitivity clash with %1").arg(newDirStr) );
@@ -174,6 +195,11 @@ void PropagateLocalMkdir::start()
     done(SyncFileItem::Success);
 }
 
+void PropagateLocalMkdir::setDeleteExistingFile(bool enabled)
+{
+    _deleteExistingFile = enabled;
+}
+
 void PropagateLocalRename::start()
 {
     if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
index 5ad01c7daafcb3247cd158a1bcf5eb65c12a5547..2b3b9a490f515e2b483b843c27926b4c6c254cc6 100644 (file)
@@ -54,9 +54,20 @@ private:
 class PropagateLocalMkdir : public PropagateItemJob {
     Q_OBJECT
 public:
-    PropagateLocalMkdir (OwncloudPropagator* propagator,const SyncFileItemPtr& item)  : PropagateItemJob(propagator, item) {}
+    PropagateLocalMkdir (OwncloudPropagator* propagator,const SyncFileItemPtr& item)
+        : PropagateItemJob(propagator, item), _deleteExistingFile(false) {}
     void start() Q_DECL_OVERRIDE;
 
+    /**
+     * Whether an existing file with the same name may be deleted before
+     * creating the directory.
+     *
+     * Default: false.
+     */
+    void setDeleteExistingFile(bool enabled);
+
+private:
+    bool _deleteExistingFile;
 };
 
 /**