Explorar el Código

vfs: Separate vfs availability from new-files-virtual

This helps support 2.5 settings where there are virtual files in the
tree but new files aren't created virtual.

It's also a prelude for #6815

There's currently no way of
- upgrading vfs plugins (a silent suffix->winvfs upgrade is attempted
  once only, when moving to master)
- disabling vfs capabilities outright
Christian Kamm hace 7 años
padre
commit
305d439c41

+ 7 - 5
src/gui/accountsettings.cpp

@@ -418,7 +418,7 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
     ac = menu->addAction(tr("Edit Ignored Files"));
     connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentIgnoredFiles);
 
-    if (!_ui->_folderList->isExpanded(index) && !folder->useVirtualFiles()) {
+    if (!_ui->_folderList->isExpanded(index) && !folder->newFilesAreVirtual()) {
         ac = menu->addAction(tr("Choose what to sync"));
         ac->setEnabled(folderConnected);
         connect(ac, &QAction::triggered, this, &AccountSettings::doExpand);
@@ -439,21 +439,21 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
     ac = menu->addAction(tr("Remove folder sync connection"));
     connect(ac, &QAction::triggered, this, &AccountSettings::slotRemoveCurrentFolder);
 
-    if (Theme::instance()->showVirtualFilesOption() || folder->useVirtualFiles()) {
+    if (Theme::instance()->showVirtualFilesOption() || folder->newFilesAreVirtual()) {
         ac = menu->addAction(tr("Create virtual files for new files (Experimental)"));
         ac->setCheckable(true);
-        ac->setChecked(folder->useVirtualFiles());
+        ac->setChecked(folder->newFilesAreVirtual());
         connect(ac, &QAction::toggled, this, [folder, this](bool checked) {
             if (!checked) {
                 if (folder)
-                    folder->setUseVirtualFiles(false);
+                    folder->setNewFilesAreVirtual(false);
                 // Make sure the size is recomputed as the virtual file indicator changes
                 _ui->_folderList->doItemsLayout();
                 return;
             }
             OwncloudWizard::askExperimentalVirtualFilesFeature([folder, this](bool enable) {
                 if (enable && folder)
-                    folder->setUseVirtualFiles(enable);
+                    folder->setNewFilesAreVirtual(enable);
 
                 // Also wipe selective sync settings
                 bool ok = false;
@@ -538,6 +538,8 @@ void AccountSettings::slotFolderWizardAccepted()
 
     if (folderWizard->property("useVirtualFiles").toBool()) {
         definition.virtualFilesMode = bestAvailableVfsMode();
+        if (definition.virtualFilesMode != Vfs::Off)
+            definition.newFilesAreVirtual = true;
     }
 
     {

+ 23 - 10
src/gui/folder.cpp

@@ -120,7 +120,9 @@ Folder::Folder(const FolderDefinition &definition,
 
     // Potentially upgrade suffix vfs to windows vfs
     ENFORCE(_vfs);
-    if (_definition.virtualFilesMode == Vfs::WithSuffix && _definition.upgradeVfsMode) {
+    if (_definition.virtualFilesMode == Vfs::WithSuffix
+        && _definition.upgradeVfsMode
+        && isVfsPluginAvailable(Vfs::WindowsCfApi)) {
         if (auto winvfs = createVfsFromPlugin(Vfs::WindowsCfApi)) {
             // Wipe the existing suffix files from fs and journal
             SyncEngine::wipeVirtualFiles(path(), _journal, *_vfs);
@@ -619,7 +621,7 @@ void Folder::dehydrateFile(const QString &_relativepath)
     slotScheduleThisFolder();
 }
 
-void Folder::setUseVirtualFiles(bool enabled)
+void Folder::setSupportsVirtualFiles(bool enabled)
 {
     Vfs::Mode newMode = _definition.virtualFilesMode;
     if (enabled && _definition.virtualFilesMode == Vfs::Off) {
@@ -645,6 +647,17 @@ void Folder::setUseVirtualFiles(bool enabled)
     }
 }
 
+bool Folder::newFilesAreVirtual() const
+{
+    return _definition.newFilesAreVirtual;
+}
+
+void Folder::setNewFilesAreVirtual(bool enabled)
+{
+    _definition.newFilesAreVirtual = enabled;
+    saveToSettings();
+}
+
 void Folder::saveToSettings() const
 {
     // Remove first to make sure we don't get duplicates
@@ -659,7 +672,7 @@ void Folder::saveToSettings() const
         return other != this && other->cleanPath() == this->cleanPath();
     });
 
-    if (useVirtualFiles() || _saveInFoldersWithPlaceholders) {
+    if (supportsVirtualFiles() || _saveInFoldersWithPlaceholders) {
         // If virtual files are enabled or even were enabled at some point,
         // save the folder to a group that will not be read by older (<2.5.0) clients.
         // The name is from when virtual files were called placeholders.
@@ -828,6 +841,7 @@ void Folder::setSyncOptions()
     opt._confirmExternalStorage = cfgFile.confirmExternalStorage();
     opt._moveFilesToTrash = cfgFile.moveToTrash();
     opt._vfs = _vfs;
+    opt._newFilesAreVirtual = _definition.newFilesAreVirtual;
 
     QByteArray chunkSizeEnv = qgetenv("OWNCLOUD_CHUNK_SIZE");
     if (!chunkSizeEnv.isEmpty()) {
@@ -1187,7 +1201,7 @@ void Folder::registerFolderWatcher()
     _folderWatcher->startNotificatonTest(path() + QLatin1String(".owncloudsync.log"));
 }
 
-bool Folder::useVirtualFiles() const
+bool Folder::supportsVirtualFiles() const
 {
     return _definition.virtualFilesMode != Vfs::Off;
 }
@@ -1234,11 +1248,10 @@ void FolderDefinition::save(QSettings &settings, const FolderDefinition &folder)
     settings.setValue(QLatin1String("paused"), folder.paused);
     settings.setValue(QLatin1String("ignoreHiddenFiles"), folder.ignoreHiddenFiles);
     settings.setValue(QLatin1String(versionC), maxSettingsVersion());
+    settings.setValue(QLatin1String("usePlaceholders"), folder.newFilesAreVirtual);
 
     settings.setValue(QStringLiteral("virtualFilesMode"), Vfs::modeToString(folder.virtualFilesMode));
 
-    // to support older versions: there usePlaceholders means suffix placeholders
-    settings.setValue(QLatin1String("usePlaceholders"), folder.virtualFilesMode == Vfs::WithSuffix);
 
     // Happens only on Windows when the explorer integration is enabled.
     if (!folder.navigationPaneClsid.isNull())
@@ -1259,17 +1272,17 @@ bool FolderDefinition::load(QSettings &settings, const QString &alias,
     folder->paused = settings.value(QLatin1String("paused")).toBool();
     folder->ignoreHiddenFiles = settings.value(QLatin1String("ignoreHiddenFiles"), QVariant(true)).toBool();
     folder->navigationPaneClsid = settings.value(QLatin1String("navigationPaneClsid")).toUuid();
+    folder->newFilesAreVirtual = settings.value(QLatin1String("usePlaceholders")).toBool();
 
-    folder->virtualFilesMode = Vfs::Off;
+    folder->virtualFilesMode = Vfs::WithSuffix;
     QString vfsModeString = settings.value(QStringLiteral("virtualFilesMode")).toString();
     if (!vfsModeString.isEmpty()) {
         if (auto mode = Vfs::modeFromString(vfsModeString)) {
             folder->virtualFilesMode = *mode;
         } else {
-            qCWarning(lcFolder) << "Unknown virtualFilesMode:" << vfsModeString << "assuming 'off'";
+            qCWarning(lcFolder) << "Unknown virtualFilesMode:" << vfsModeString << "assuming 'suffix'";
         }
-    } else if (settings.value(QLatin1String("usePlaceholders")).toBool()) {
-        folder->virtualFilesMode = Vfs::WithSuffix;
+    } else {
         folder->upgradeVfsMode = true;
     }
 

+ 15 - 5
src/gui/folder.h

@@ -63,11 +63,12 @@ public:
     bool ignoreHiddenFiles = false;
     /// Which virtual files setting the folder uses
     Vfs::Mode virtualFilesMode = Vfs::Off;
+    /// Whether new files are virtual
+    bool newFilesAreVirtual = false;
     /// The CLSID where this folder appears in registry for the Explorer navigation pane entry.
     QUuid navigationPaneClsid;
 
-    /// Whether this suffix-vfs should be migrated to a better
-    /// vfs plugin if possible
+    /// Whether the vfs mode shall silently be updated if possible
     bool upgradeVfsMode = false;
 
     /// Saves the folder definition, creating a new settings group.
@@ -249,9 +250,18 @@ public:
      */
     void registerFolderWatcher();
 
-    /** virtual files of some kind are enabled */
-    bool useVirtualFiles() const;
-    void setUseVirtualFiles(bool enabled);
+    /** virtual files of some kind are enabled
+     *
+     * This is independent of whether new files will be virtual. It's possible to have this enabled
+     * and never have an automatic virtual file. But when it's on, the shell context menu will allow
+     * users to make existing files virtual.
+     */
+    bool supportsVirtualFiles() const;
+    void setSupportsVirtualFiles(bool enabled);
+
+    /** whether new remote files shall become virtual locally */
+    bool newFilesAreVirtual() const;
+    void setNewFilesAreVirtual(bool enabled);
 
 signals:
     void syncStateChange();

+ 4 - 4
src/gui/folderstatusmodel.cpp

@@ -219,7 +219,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
     case FolderStatusDelegate::FolderErrorMsg:
         return f->syncResult().errorStrings();
     case FolderStatusDelegate::FolderInfoMsg:
-        return f->useVirtualFiles()
+        return f->newFilesAreVirtual()
             ? QStringList(tr("New files are being created as virtual files."))
             : QStringList();
     case FolderStatusDelegate::SyncRunning:
@@ -370,7 +370,7 @@ int FolderStatusModel::rowCount(const QModelIndex &parent) const
     auto info = infoForIndex(parent);
     if (!info)
         return 0;
-    if (info->_folder && info->_folder->useVirtualFiles())
+    if (info->_folder && info->_folder->newFilesAreVirtual())
         return 0;
     if (info->hasLabel())
         return 1;
@@ -527,7 +527,7 @@ bool FolderStatusModel::hasChildren(const QModelIndex &parent) const
     if (!info)
         return false;
 
-    if (info->_folder && info->_folder->useVirtualFiles())
+    if (info->_folder && info->_folder->newFilesAreVirtual())
         return false;
 
     if (!info->_fetched)
@@ -555,7 +555,7 @@ bool FolderStatusModel::canFetchMore(const QModelIndex &parent) const
         // Keep showing the error to the user, it will be hidden when the account reconnects
         return false;
     }
-    if (info->_folder && info->_folder->useVirtualFiles()) {
+    if (info->_folder && info->_folder->newFilesAreVirtual()) {
         // Selective sync is hidden in that case
         return false;
     }

+ 2 - 0
src/gui/owncloudsetupwizard.cpp

@@ -637,6 +637,8 @@ void OwncloudSetupWizard::slotAssistantFinished(int result)
             folderDefinition.ignoreHiddenFiles = folderMan->ignoreHiddenFiles();
             if (_ocWizard->useVirtualFileSync()) {
                 folderDefinition.virtualFilesMode = bestAvailableVfsMode();
+                if (folderDefinition.virtualFilesMode != Vfs::Off)
+                    folderDefinition.newFilesAreVirtual = true;
             }
             if (folderMan->navigationPaneHelper().showInExplorerNavigationPane())
                 folderDefinition.navigationPaneClsid = QUuid::createUuid();

+ 2 - 2
src/gui/socketapi.cpp

@@ -1003,10 +1003,10 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe
                 }
             }
         }
-        if (hasVirtualFile || (hasDir && syncFolder->useVirtualFiles()))
+        if (hasVirtualFile || (hasDir && syncFolder->supportsVirtualFiles()))
             listener->sendMessage(QLatin1String("MENU_ITEM:DOWNLOAD_VIRTUAL_FILE::") + tr("Download file(s)", "", files.size()));
 
-        if ((hasNormalFiles || hasDir) && syncFolder->useVirtualFiles())
+        if ((hasNormalFiles || hasDir) && syncFolder->supportsVirtualFiles())
             listener->sendMessage(QLatin1String("MENU_ITEM:REPLACE_VIRTUAL_FILE::") + tr("Replace file(s) by virtual file", "", files.size()));
     }
 

+ 2 - 2
src/libsync/discovery.cpp

@@ -399,8 +399,8 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
             return;
         }
         // Turn new remote files into virtual files if the option is enabled.
-        auto &vfs = _discoveryData->_syncOptions._vfs;
-        if (!localEntry.isValid() && vfs->mode() != Vfs::Off && item->_type == ItemTypeFile) {
+        auto &opts = _discoveryData->_syncOptions;
+        if (!localEntry.isValid() && opts._vfs->mode() != Vfs::Off && opts._newFilesAreVirtual && item->_type == ItemTypeFile) {
             item->_type = ItemTypeVirtualFile;
             if (isVfsWithSuffix())
                 addVirtualFileSuffix(path._original);

+ 1 - 1
src/libsync/discoveryphase.cpp

@@ -100,7 +100,7 @@ void DiscoveryPhase::checkSelectiveSyncNewFolder(const QString &path, RemotePerm
     }
 
     auto limit = _syncOptions._newBigFolderSizeLimit;
-    if (limit < 0 || _syncOptions._vfs->mode() != Vfs::Off) {
+    if (limit < 0 || (_syncOptions._vfs->mode() != Vfs::Off && _syncOptions._newFilesAreVirtual)) {
         // no limit, everything is allowed;
         return callback(false);
     }

+ 3 - 0
src/libsync/syncoptions.h

@@ -44,6 +44,9 @@ struct SyncOptions
     /** Create a virtual file for new files instead of downloading. May not be null */
     QSharedPointer<Vfs> _vfs;
 
+    /** True if new files shall be virtual */
+    bool _newFilesAreVirtual = false;
+
     /** The initial un-adjusted chunk size in bytes for chunked uploads, both
      * for old and new chunking algorithm, which classifies the item to be chunked
      *

+ 7 - 51
test/testsyncvirtualfiles.cpp

@@ -63,6 +63,7 @@ SyncOptions vfsSyncOptions()
 {
     SyncOptions options;
     options._vfs.reset(createVfsFromPlugin(Vfs::WithSuffix).release());
+    options._newFilesAreVirtual = true;
     return options;
 }
 
@@ -418,71 +419,26 @@ private slots:
         QVERIFY(!dbRecord(fakeFolder, "A/a1.nextcloud").isValid());
     }
 
-    // Check what happens if vfs mode is disabled
-    void testSwitchOfVfs()
+    void testNewFilesNotVirtual()
     {
-        QSKIP("Does not work with the new discovery because the way we simulate the old client does not work");
         FakeFolder fakeFolder{ FileInfo() };
         SyncOptions syncOptions = vfsSyncOptions();
         fakeFolder.syncEngine().setSyncOptions(syncOptions);
         QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
 
-        // Create a virtual file
         fakeFolder.remoteModifier().mkdir("A");
         fakeFolder.remoteModifier().insert("A/a1");
         QVERIFY(fakeFolder.syncOnce());
         QVERIFY(fakeFolder.currentLocalState().find("A/a1.nextcloud"));
 
-        // Switch off new files becoming virtual files
-        syncOptions._vfs.reset(new VfsOff);
+        syncOptions._newFilesAreVirtual = false;
         fakeFolder.syncEngine().setSyncOptions(syncOptions);
 
-        // A sync that doesn't do remote discovery will wipe the placeholder, but not redownload
-        QVERIFY(fakeFolder.syncOnce());
-        QVERIFY(!fakeFolder.currentLocalState().find("A/a1.nextcloud"));
-        QVERIFY(!fakeFolder.currentLocalState().find("A/a1"));
-        QVERIFY(fakeFolder.currentRemoteState().find("A/a1"));
-        QVERIFY(!fakeFolder.currentRemoteState().find("A/a1.nextcloud"));
-
-        // But with a remote discovery the virtual files will be removed and
-        // the remote files will be downloaded.
-        fakeFolder.syncJournal().forceRemoteDiscoveryNextSync();
-        QVERIFY(fakeFolder.syncOnce());
-        QVERIFY(fakeFolder.currentLocalState().find("A/a1"));
-        QVERIFY(!fakeFolder.currentLocalState().find("A/a1.nextcloud"));
-        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
-    }
-
-    // Older versions may leave db entries for foo and foo.nextcloud
-    void testOldVersion2()
-    {
-        QSKIP("Does not work with the new discovery because the way we simulate the old client does not work");
-        FakeFolder fakeFolder{ FileInfo() };
-
-        // Sync a file
-        fakeFolder.remoteModifier().mkdir("A");
-        fakeFolder.remoteModifier().insert("A/a1");
-        QVERIFY(fakeFolder.syncOnce());
-        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
-
-        // Create the virtual file too
-        // In the wild, the new version would create the virtual file and the db entry
-        // while the old version would download the plain file.
-        fakeFolder.localModifier().insert("A/a1.nextcloud");
-        auto &db = fakeFolder.syncJournal();
-        SyncJournalFileRecord rec;
-        db.getFileRecord(QByteArray("A/a1"), &rec);
-        rec._type = ItemTypeVirtualFile;
-        rec._path = "A/a1.nextcloud";
-        db.setFileRecord(rec);
-
-        fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions());
-
-        // Check that a sync removes the virtual file and its db entry
+        // Create a new remote file, it'll not be virtual
+        fakeFolder.remoteModifier().insert("A/a2");
         QVERIFY(fakeFolder.syncOnce());
-        QVERIFY(!fakeFolder.currentLocalState().find("A/a1.nextcloud"));
-        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
-        QVERIFY(!dbRecord(fakeFolder, "A/a1.nextcloud").isValid());
+        QVERIFY(fakeFolder.currentLocalState().find("A/a2"));
+        QVERIFY(!fakeFolder.currentLocalState().find("A/a2.nextcloud"));
     }
 
     void testDownloadRecursive()