[Pkg-owncloud-commits] [owncloud-client] 97/332: sync engine: try to respect permission

Sandro Knauß hefee-guest at moszumanska.debian.org
Thu Aug 14 21:06:44 UTC 2014


This is an automated email from the git hooks/post-receive script.

hefee-guest pushed a commit to branch master
in repository owncloud-client.

commit b83f6c0b3ae01ebf991ecfc8c15ee2271cdf78dd
Author: Olivier Goffart <ogoffart at woboq.com>
Date:   Sat Jun 7 11:49:46 2014 +0200

    sync engine: try to respect permission
    
    This is still Work in progress
---
 src/mirall/owncloudpropagator.cpp |  10 ++-
 src/mirall/owncloudpropagator.h   |  10 ++-
 src/mirall/syncengine.cpp         | 185 ++++++++++++++++++++++++++++++++++++++
 src/mirall/syncengine.h           |   7 ++
 src/mirall/syncfileitem.h         |   3 +-
 5 files changed, 210 insertions(+), 5 deletions(-)

diff --git a/src/mirall/owncloudpropagator.cpp b/src/mirall/owncloudpropagator.cpp
index 0003b0e..8644d6f 100644
--- a/src/mirall/owncloudpropagator.cpp
+++ b/src/mirall/owncloudpropagator.cpp
@@ -43,7 +43,15 @@ static int maximumActiveJob() {
 
 void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorString)
 {
-    _item._errorString = errorString;
+    if (_item._isRestoration) {
+        if( status == SyncFileItem::Success || status == SyncFileItem::Conflict) {
+            status = SyncFileItem::SoftError;
+        } else {
+            _item._errorString += tr("; Restoration Failed: ") + errorString;
+        }
+    } else {
+        _item._errorString = errorString;
+    }
     _item._status = status;
 
     // Blacklisting
diff --git a/src/mirall/owncloudpropagator.h b/src/mirall/owncloudpropagator.h
index 33146aa..ab99ef2 100644
--- a/src/mirall/owncloudpropagator.h
+++ b/src/mirall/owncloudpropagator.h
@@ -139,11 +139,15 @@ protected:
      * set a custom restore job message that is used if the restore job succeeded.
      * It is displayed in the activity view.
      */
-    QString restoreJobMsg() const { return _restoreJobMsg; }
-    void setRestoreJobMsg( const QString& msg = QString() ) { _restoreJobMsg = msg; }
+    QString restoreJobMsg() const {
+        return _item._isRestoration ? _item._errorString : QString();
+    }
+    void setRestoreJobMsg( const QString& msg = QString() ) {
+        _item._isRestoration = true;
+        _item._errorString = msg;
+    }
 
     SyncFileItem  _item;
-    QString       _restoreJobMsg;
 
 protected slots:
     void slotRestoreJobCompleted(const SyncFileItem& );
diff --git a/src/mirall/syncengine.cpp b/src/mirall/syncengine.cpp
index 65267d1..3d391aa 100644
--- a/src/mirall/syncengine.cpp
+++ b/src/mirall/syncengine.cpp
@@ -526,6 +526,7 @@ void SyncEngine::slotUpdateFinished(int updateResult)
         handleSyncError(_csync_ctx, "csync_reconcile");
         return;
     }
+
     _stopWatch.addLapTime(QLatin1String("Reconcile Finished"));
 
     _progressInfo = Progress::Info();
@@ -548,6 +549,9 @@ void SyncEngine::slotUpdateFinished(int updateResult)
         it->_file = adjustRenamedPath(it->_file);
     }
 
+    // make sure everything is allowed
+    checkForPermission();
+
     // Sanity check
     if (!_journal->isConnected()) {
         qDebug() << "Bailing out, DB failure";
@@ -698,6 +702,187 @@ QString SyncEngine::adjustRenamedPath(const QString& original)
     return original;
 }
 
+void SyncEngine::checkForPermission()
+{
+    for (SyncFileItemVector::iterator it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
+
+        if (it->_direction != SyncFileItem::Up) {
+            // Currently we only check server-side permissions
+            continue;
+        }
+
+        switch(it->_instruction) {
+            case CSYNC_INSTRUCTION_NEW: {
+                int slashPos = it->_file.lastIndexOf('/');
+                QString parentDir = slashPos <= 0 ? "" : it->_file.mid(0, slashPos);
+                const QByteArray perms = getPermissions(parentDir);
+                if (perms.isNull()) {
+                    // No permissions set
+                    break;
+                } else if (it->_isDirectory && !perms.contains("K")) {
+                    qDebug() << "checkForPermission: ERROR" << it->_file;
+                    it->_instruction = CSYNC_INSTRUCTION_ERROR;
+                    it->_status = SyncFileItem::NormalError;
+                    it->_errorString = tr("Not allowed because you don't have permission to add sub-directories in that directory");
+
+                    const QString path = it->_file + QLatin1Char('/');
+                    for (SyncFileItemVector::iterator it_next = it + 1; it_next != _syncedItems.end() && it_next->_file.startsWith(path); ++it_next) {
+                        it = it_next;
+                        it->_instruction = CSYNC_INSTRUCTION_ERROR;
+                        it->_status = SyncFileItem::NormalError;
+                        it->_errorString = tr("Not allowed because you don't have permission to add parent directory");
+                    }
+
+                } else if (!it->_isDirectory && !perms.contains("C")) {
+                    qDebug() << "checkForPermission: ERROR" << it->_file;
+                    it->_instruction = CSYNC_INSTRUCTION_ERROR;
+                    it->_status = SyncFileItem::NormalError;
+                    it->_errorString = tr("Not allowed because you don't have permission to add files in that directory");
+                }
+                break;
+            }
+            case CSYNC_INSTRUCTION_SYNC: {
+                const QByteArray perms = getPermissions(it->_file);
+                if (perms.isNull()) {
+                    // No permissions set
+                    break;
+                } if (!it->_isDirectory && !perms.contains("W")) {
+                    qDebug() << "checkForPermission: RESTORING" << it->_file;
+                    it->_instruction = CSYNC_INSTRUCTION_CONFLICT;
+                    it->_direction = SyncFileItem::Down;
+                    it->_isRestoration = true;
+                    it->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring");
+                    continue;
+                }
+                break;
+            }
+            case CSYNC_INSTRUCTION_REMOVE: {
+                const QByteArray perms = getPermissions(it->_file);
+                if (perms.isNull()) {
+                    // No permissions set
+                    break;
+                } if (!perms.contains("D")) {
+                    qDebug() << "checkForPermission: RESTORING" << it->_file;
+                    it->_instruction = CSYNC_INSTRUCTION_NEW;
+                    it->_direction = SyncFileItem::Down;
+                    it->_isRestoration = true;
+                    it->_errorString = tr("Not allowed to remove, restoring");
+
+                    if (it->_isDirectory) {
+                        // restore all sub items
+                        const QString path = it->_file + QLatin1Char('/');
+                        for (SyncFileItemVector::iterator it_next = it + 1;
+                             it_next != _syncedItems.end() && it_next->_file.startsWith(path); ++it_next) {
+                            it = it_next;
+
+                            if (it->_instruction != CSYNC_INSTRUCTION_REMOVE) {
+                                qWarning() << "non-removed job within a removed directory"
+                                           << it->_file << it->_instruction;
+                                continue;
+                            }
+
+                            qDebug() << "checkForPermission: RESTORING" << it->_file;
+
+                            it->_instruction = CSYNC_INSTRUCTION_NEW;
+                            it->_direction = SyncFileItem::Down;
+                            it->_isRestoration = true;
+                            it->_errorString = tr("Not allowed to remove, restoring");
+                        }
+                    }
+                }
+                break;
+            }
+
+            case CSYNC_INSTRUCTION_RENAME: {
+
+                int slashPos = it->_renameTarget.lastIndexOf('/');
+                const QString parentDir = slashPos <= 0 ? "" : it->_renameTarget.mid(0, slashPos-1);
+                const QByteArray destPerms = getPermissions(parentDir);
+                const QByteArray filePerms = getPermissions(it->_file);
+
+                //true when it is just a rename in the same directory. (not a move)
+                bool isRename = it->_file.startsWith(parentDir) && it->_file.lastIndexOf('/') == slashPos;
+
+
+                // Check if we are allowed to move to the destination.
+                bool destinationOK = true;
+                if (isRename || destPerms.isNull()) {
+                    // no need to check for the destination dir permission
+                    destinationOK = true;
+                } else if (it->_isDirectory && !destPerms.contains("K")) {
+                    destinationOK = false;
+                } else if (!it->_isDirectory && !destPerms.contains("C")) {
+                    destinationOK = false;
+                }
+
+                // check if we are allowed to move from the source
+                bool sourceOK = true;
+                if (!filePerms.isNull()
+                    &&  ((isRename && !filePerms.contains("N"))
+                         || (!isRename && !filePerms.contains("M")))) {
+
+                    // We are not allowed to move or rename this file
+                    sourceOK = false;
+
+                    if (filePerms.contains("D") && destinationOK) {
+                        // but we are allowed to delete it
+                        // TODO!  simulate delete & upload
+                    }
+                }
+
+                if (!sourceOK && !destinationOK) {
+                    // Both the source and the destination won't allow move.  Move back to the original
+                    std::swap(it->_file, it->_renameTarget);
+                    it->_direction = SyncFileItem::Down;
+                    it->_errorString = tr("Move not allowed, item restored");
+                    it->_isRestoration = true;
+                    qDebug() << "checkForPermission: MOVING BACK" << it->_file;
+                } else if (!sourceOK || !destinationOK) {
+                    // One of them is not possible, just throw an error
+                    it->_instruction = CSYNC_INSTRUCTION_ERROR;
+                    it->_status = SyncFileItem::NormalError;
+                    const QString errorString = tr("Move not allowed because %1 is read-only").arg(
+                        sourceOK ? tr("the destination") : tr("the source"));
+                    it->_errorString = errorString;
+
+                    qDebug() << "checkForPermission: ERROR MOVING" << it->_file << errorString;
+
+                    if (it->_isDirectory) {
+                        const QString path = it->_file + QLatin1Char('/');
+                        for (SyncFileItemVector::iterator it_next = it + 1;
+                             it_next != _syncedItems.end() && it_next->_file.startsWith(path); ++it_next) {
+                            it = it_next;
+                            it->_instruction = CSYNC_INSTRUCTION_ERROR;
+                            it->_status = SyncFileItem::NormalError;
+                            it->_errorString = errorString;
+                            qDebug() << "checkForPermission: ERROR MOVING" << it->_file;
+                        }
+                    }
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+QByteArray SyncEngine::getPermissions(const QString& file)
+{
+    //FIXME;
+    static bool isTest = qgetenv("OWNCLOUD_TEST_PERMISSIONS").toInt();
+    if (isTest) {
+        QRegExp rx("_PERM_([^_]*)_[^/]*$");
+        if (rx.indexIn(file) != -1) {
+            qDebug() << Q_FUNC_INFO << file << rx.cap(1);
+            return rx.cap(1).toLatin1();
+        }
+    }
+    qDebug() << Q_FUNC_INFO << file << "*" << isTest;
+    return QByteArray();
+}
+
+
 void SyncEngine::abort()
 {
     csync_request_abort(_csync_ctx);
diff --git a/src/mirall/syncengine.h b/src/mirall/syncengine.h
index 6aeb384..cb45f32 100644
--- a/src/mirall/syncengine.h
+++ b/src/mirall/syncengine.h
@@ -126,6 +126,13 @@ private:
     QHash<QString, QString> _renamedFolders;
     QString adjustRenamedPath(const QString &original);
 
+    /**
+     * check if we are allowed to propagate everything, and if we are not, adjust the instructions
+     * to recover
+     */
+    void checkForPermission();
+    QByteArray getPermissions(const QString& file);
+
     bool _hasFiles; // true if there is at least one file that is not ignored or removed
 
     int _uploadLimit;
diff --git a/src/mirall/syncfileitem.h b/src/mirall/syncfileitem.h
index b869a3d..2dc882a 100644
--- a/src/mirall/syncfileitem.h
+++ b/src/mirall/syncfileitem.h
@@ -51,7 +51,7 @@ public:
 
     SyncFileItem() : _type(UnknownType),  _direction(None), _instruction(CSYNC_INSTRUCTION_NONE),
         _size(0), _should_update_etag(false), _blacklistedInDb(false),
-        _status(NoStatus), _httpErrorCode(0), _requestDuration(0) {}
+        _status(NoStatus), _httpErrorCode(0), _requestDuration(0), _isRestoration(false) {}
 
     friend bool operator==(const SyncFileItem& item1, const SyncFileItem& item2) {
         return item1._file == item2._file;
@@ -97,6 +97,7 @@ public:
     int                  _httpErrorCode;
     QString              _responseTimeStamp;
     quint64              _requestDuration;
+    bool                 _isRestoration; // The original operation was forbidden, and this is a restoration
 
     struct {
         quint64     _size;

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