Folder: Add remoteFolderTrailingSlash()
authorChristian Kamm <mail@ckamm.de>
Fri, 25 Jan 2019 06:46:16 +0000 (07:46 +0100)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:39 +0000 (10:58 +0100)
There were cases where the "/" exception wasn't handled correctly
and there'd be extra slashes in generated paths.

src/common/vfs.h
src/gui/folder.cpp
src/gui/folder.h
src/gui/folderman.cpp
src/gui/folderstatusmodel.cpp
src/gui/folderwizard.cpp
src/gui/sharemanager.cpp
test/syncenginetestutils.h

index 179f0174d38deb0d7bcd268f9ec69c047f24a7bf..c57e9349f30af5c731f7721a3344c99776444bc3 100644 (file)
@@ -37,9 +37,16 @@ class SyncFileItem;
 /** Collection of parameters for initializing a Vfs instance. */
 struct OCSYNC_EXPORT VfsSetupParams
 {
-    /// The full path to the folder on the local filesystem
+    /** The full path to the folder on the local filesystem
+     *
+     * Always ends with /.
+     */
     QString filesystemPath;
-    /// The path to the synced folder on the account
+
+    /** The path to the synced folder on the account
+     *
+     * Always ends with /.
+     */
     QString remotePath;
 
     /// Account url, credentials etc for network calls
index 8674068e329869558fe1a4c0f014fe68d4ae1b41..9828a495c9dd8a3acd87d0baab1503de59da433d 100644 (file)
@@ -256,6 +256,14 @@ QString Folder::remotePath() const
     return _definition.targetPath;
 }
 
+QString Folder::remotePathTrailingSlash() const
+{
+    QString result = remotePath();
+    if (!result.endsWith('/'))
+        result.append('/');
+    return result;
+}
+
 QUrl Folder::remoteUrl() const
 {
     return Utility::concatUrlPath(_accountState->account()->davUrl(), remotePath());
@@ -476,7 +484,7 @@ void Folder::startVfs()
 
     VfsSetupParams vfsParams;
     vfsParams.filesystemPath = path();
-    vfsParams.remotePath = remotePath();
+    vfsParams.remotePath = remotePathTrailingSlash();
     vfsParams.account = _accountState->account();
     vfsParams.journal = &_journal;
     vfsParams.providerName = Theme::instance()->appNameGUI();
@@ -1303,7 +1311,7 @@ bool FolderDefinition::load(QSettings &settings, const QString &alias,
     }
 
     // Old settings can contain paths with native separators. In the rest of the
-    // code we assum /, so clean it up now.
+    // code we assume /, so clean it up now.
     folder->localPath = prepareLocalPath(folder->localPath);
 
     // Target paths also have a convention
index 4a3c544a2a9e3fa221442611bba51a92a5c6cb21..75fe0b2c580398556f5548462d95b91f1e83c879 100644 (file)
@@ -51,11 +51,11 @@ class FolderDefinition
 public:
     /// The name of the folder in the ui and internally
     QString alias;
-    /// path on local machine
+    /// path on local machine (always trailing /)
     QString localPath;
     /// path to the journal, usually relative to localPath
     QString journalPath;
-    /// path on remote
+    /// path on remote (usually no trailing /, exception "/")
     QString targetPath;
     /// whether the folder is paused
     bool paused = false;
@@ -88,7 +88,7 @@ public:
     /// Ensure / as separator and trailing /.
     static QString prepareLocalPath(const QString &path);
 
-    /// Ensure starting / and no ending /.
+    /// Remove ending /, then ensure starting '/': so "/foo/bar" and "/".
     static QString prepareTargetPath(const QString &path);
 
     /// journalPath relative to localPath.
@@ -146,10 +146,15 @@ public:
     QString cleanPath() const;
 
     /**
-     * remote folder path
+     * remote folder path, usually without trailing /, exception "/"
      */
     QString remotePath() const;
 
+    /**
+     * remote folder path, always with a trailing /
+     */
+    QString remotePathTrailingSlash() const;
+
     void setNavigationPaneClsid(const QUuid &clsid) { _definition.navigationPaneClsid = clsid; }
     QUuid navigationPaneClsid() const { return _definition.navigationPaneClsid; }
 
index 79be36c3ebc1688dda38cb66d68e72dd5815aeeb..b690a86d44e4dbf9447fa281716240270e523086 100644 (file)
@@ -1091,16 +1091,20 @@ QStringList FolderMan::findFileInLocalFolders(const QString &relPath, const Acco
 {
     QStringList re;
 
+    // We'll be comparing against Folder::remotePath which always starts with /
+    QString serverPath = relPath;
+    if (!serverPath.startsWith('/'))
+        serverPath.prepend('/');
+
     for (Folder *folder : this->map().values()) {
         if (acc && folder->accountState()->account() != acc) {
             continue;
         }
-        QString path = folder->cleanPath();
-        QString remRelPath;
-        // cut off the remote path from the server path.
-        remRelPath = relPath.mid(folder->remotePath().length());
-        path += "/";
-        path += remRelPath;
+        if (!serverPath.startsWith(folder->remotePath()))
+            continue;
+
+        QString path = folder->cleanPath() + '/';
+        path += serverPath.midRef(folder->remotePathTrailingSlash().length());
         if (QFile::exists(path)) {
             re.append(path);
         }
index af010f99a3743af98cdb59e929c69ba16956d65c..45678d0a662497e95e509f36226280d42c8d3a0b 100644 (file)
@@ -570,11 +570,8 @@ void FolderStatusModel::fetchMore(const QModelIndex &parent)
     if (!info || info->_fetched || info->_fetchingJob)
         return;
     info->resetSubs(this, parent);
-    QString path = info->_folder->remotePath();
+    QString path = info->_folder->remotePathTrailingSlash();
     if (info->_path != QLatin1String("/")) {
-        if (!path.endsWith(QLatin1Char('/'))) {
-            path += QLatin1Char('/');
-        }
         path += info->_path;
     }
 
index 32cfc7b6198d07ea7b6b74b1549c225b6ff6cd42..ab109316ed1fe4f957f0b3d91f452000ba3f56f1 100644 (file)
@@ -449,13 +449,10 @@ bool FolderWizardRemotePath::isComplete() const
         if (f->accountState()->account() != _account) {
             continue;
         }
-        QString curDir = f->remotePath();
-        if (!curDir.startsWith(QLatin1Char('/'))) {
-            curDir.prepend(QLatin1Char('/'));
-        }
+        QString curDir = f->remotePathTrailingSlash();
         if (QDir::cleanPath(dir) == QDir::cleanPath(curDir)) {
             warnStrings.append(tr("This folder is already being synced."));
-        } else if (dir.startsWith(curDir + QLatin1Char('/'))) {
+        } else if (dir.startsWith(curDir)) {
             warnStrings.append(tr("You are already syncing <i>%1</i>, which is a parent folder of <i>%2</i>.").arg(Utility::escape(curDir), Utility::escape(dir)));
         }
     }
index 87df91350aa4c3c57ad77a8128f9597261f9f140..ed1eea9cc53f329b2b711b9aeed79d83b17e27f5 100644 (file)
@@ -37,9 +37,7 @@ static void updateFolder(const AccountPtr &account, const QString &path)
         if (path.startsWith(folderPath) && (path == folderPath || folderPath.endsWith('/') || path[folderPath.size()] == '/')) {
             // Workaround the fact that the server does not invalidate the etags of parent directories
             // when something is shared.
-            auto relative = path.midRef(folderPath.size());
-            if (relative.startsWith('/'))
-                relative = relative.mid(1);
+            auto relative = path.midRef(f->remotePathTrailingSlash().length());
             f->journalDb()->avoidReadFromDbOnNextSync(relative.toString());
 
             // Schedule a sync so it can update the remote permission flag and let the socket API
index f3663f8ba6737066c5921a80bb091b07ef06d2c7..66f9717f6ac03b0412bdbca0c5a53b657391bf33 100644 (file)
@@ -947,7 +947,7 @@ public:
 
         OCC::VfsSetupParams vfsParams;
         vfsParams.filesystemPath = localPath();
-        vfsParams.remotePath = "";
+        vfsParams.remotePath = "/";
         vfsParams.account = _account;
         vfsParams.journal = _journalDb.get();
         vfsParams.providerName = "OC-TEST";