return {};
}
+VfsOff::VfsOff(QObject *parent)
+ : Vfs(parent)
+{
+}
+
+VfsOff::~VfsOff() = default;
+
static QString modeToPluginName(Vfs::Mode mode)
{
if (mode == Vfs::WithSuffix)
bool OCC::isVfsPluginAvailable(Vfs::Mode mode)
{
+ if (mode == Vfs::Off)
+ return true;
auto name = modeToPluginName(mode);
if (name.isEmpty())
return false;
std::unique_ptr<Vfs> OCC::createVfsFromPlugin(Vfs::Mode mode)
{
+ if (mode == Vfs::Off)
+ return std::unique_ptr<Vfs>(new VfsOff);
+
auto name = modeToPluginName(mode);
if (name.isEmpty())
return nullptr;
virtual Mode mode() const = 0;
- /// For WithSuffix modes: what's the suffix (including the dot)?
+ /// For WithSuffix modes: the suffix (including the dot)
virtual QString fileSuffix() const = 0;
void doneHydrating();
};
+/// Implementation of Vfs for Vfs::Off mode - does nothing
+class OCSYNC_EXPORT VfsOff : public Vfs
+{
+ Q_OBJECT
+
+public:
+ VfsOff(QObject* parent = nullptr);
+ virtual ~VfsOff();
+
+ Mode mode() const override { return Vfs::Off; }
+
+ QString fileSuffix() const override { return QString(); }
+
+ void registerFolder(const VfsSetupParams &) override {}
+ void start(const VfsSetupParams &) override {}
+ void stop() override {}
+ void unregisterFolder() override {}
+
+
+ bool isHydrating() const override { return false; }
+
+ bool updateMetadata(const QString &, time_t, quint64, const QByteArray &, QString *) override { return true; }
+ void createPlaceholder(const QString &, const SyncFileItemPtr &) override {}
+ void convertToPlaceholder(const QString &, const SyncFileItemPtr &) override {}
+
+ bool isDehydratedPlaceholder(const QString &) override { return false; }
+ bool statTypeVirtualFile(csync_file_stat_t *, void *) override { return false; }
+};
+
/// Check whether the plugin for the mode is available.
OCSYNC_EXPORT bool isVfsPluginAvailable(Vfs::Mode mode);
// Override type for virtual files if desired
if (vfs) {
- // Directly modifiest file_stat->type.
+ // Directly modifies file_stat->type.
// We can ignore the return value since we're done here anyway.
vfs->statTypeVirtualFile(file_stat.get(), nullptr);
}
_localDiscoveryTracker.data(), &LocalDiscoveryTracker::slotItemCompleted);
// Potentially upgrade suffix vfs to windows vfs
+ ENFORCE(_vfs);
if (_definition.virtualFilesMode == Vfs::WithSuffix && _definition.upgradeVfsMode) {
if (auto winvfs = createVfsFromPlugin(Vfs::WindowsCfApi)) {
// Wipe the existing suffix files from fs and journal
- SyncEngine::wipeVirtualFiles(path(), _journal, _vfs.data());
+ SyncEngine::wipeVirtualFiles(path(), _journal, *_vfs);
// Then switch to winvfs mode
_vfs.reset(winvfs.release());
}
// Initialize the vfs plugin
- if (_definition.virtualFilesMode != Vfs::Off)
- startVfs();
+ startVfs();
}
Folder::~Folder()
{
// TODO cfapi: unregister on wipe()? There should probably be a wipeForRemoval() where this cleanup is appropriate
- if (_vfs)
- _vfs->stop();
+ _vfs->stop();
// Reset then engine first as it will abort and try to access members of the Folder
_engine.reset();
bool Folder::isSyncRunning() const
{
- return _engine->isSyncRunning() || (_vfs && _vfs->isHydrating());
+ return _engine->isSyncRunning() || _vfs->isHydrating();
}
QString Folder::remotePath() const
void Folder::setUseVirtualFiles(bool enabled)
{
+ Vfs::Mode newMode = _definition.virtualFilesMode;
if (enabled && _definition.virtualFilesMode == Vfs::Off) {
- _definition.virtualFilesMode = bestAvailableVfsMode();
-
- _vfs.reset(createVfsFromPlugin(_definition.virtualFilesMode).release());
- startVfs();
-
- _saveInFoldersWithPlaceholders = true;
+ newMode = bestAvailableVfsMode();
+ } else if (!enabled && _definition.virtualFilesMode != Vfs::Off) {
+ newMode = Vfs::Off;
}
- if (!enabled && _definition.virtualFilesMode != Vfs::Off) {
- ENFORCE(_vfs);
+ if (newMode != _definition.virtualFilesMode) {
// TODO: Must wait for current sync to finish!
- SyncEngine::wipeVirtualFiles(path(), _journal, _vfs.data());
+ SyncEngine::wipeVirtualFiles(path(), _journal, *_vfs);
_vfs->stop();
_vfs->unregisterFolder();
- _vfs.reset(nullptr);
- _definition.virtualFilesMode = Vfs::Off;
+ _vfs.reset(createVfsFromPlugin(newMode).release());
+ startVfs();
+
+ _definition.virtualFilesMode = newMode;
+ if (newMode != Vfs::Off)
+ _saveInFoldersWithPlaceholders = true;
+ saveToSettings();
}
- saveToSettings();
}
void Folder::saveToSettings() const
opt._newBigFolderSizeLimit = newFolderLimit.first ? newFolderLimit.second * 1000LL * 1000LL : -1; // convert from MB to B
opt._confirmExternalStorage = cfgFile.confirmExternalStorage();
opt._moveFilesToTrash = cfgFile.moveToTrash();
- opt._vfs = _vfs.data();
+ opt._vfs = _vfs;
QByteArray chunkSizeEnv = qgetenv("OWNCLOUD_CHUNK_SIZE");
if (!chunkSizeEnv.isEmpty()) {
QScopedPointer<LocalDiscoveryTracker> _localDiscoveryTracker;
/**
- * The vfs mode instance (created by plugin) to use. Null means no vfs.
+ * The vfs mode instance (created by plugin) to use. Never null.
*/
- QScopedPointer<Vfs> _vfs;
+ QSharedPointer<Vfs> _vfs;
};
}
}
auto vfs = createVfsFromPlugin(folderDefinition.virtualFilesMode);
- if (!vfs && folderDefinition.virtualFilesMode != Vfs::Off) {
+ if (!vfs) {
// TODO: Must do better error handling
qFatal("Could not load plugin");
}
}
auto vfs = createVfsFromPlugin(folderDefinition.virtualFilesMode);
- if (!vfs && folderDefinition.virtualFilesMode != Vfs::Off) {
+ if (!vfs) {
qCWarning(lcFolderMan) << "Could not load plugin for mode" << folderDefinition.virtualFilesMode;
return 0;
}
return;
}
// Turn new remote files into virtual files if the option is enabled.
- auto vfs = _discoveryData->_syncOptions._vfs;
- if (!localEntry.isValid() && vfs && item->_type == ItemTypeFile) {
+ auto &vfs = _discoveryData->_syncOptions._vfs;
+ if (!localEntry.isValid() && vfs->mode() != Vfs::Off && item->_type == ItemTypeFile) {
item->_type = ItemTypeVirtualFile;
if (isVfsWithSuffix())
addVirtualFileSuffix(path._original);
void ProcessDirectoryJob::addVirtualFileSuffix(QString &str) const
{
- if (auto vfs = _discoveryData->_syncOptions._vfs)
- str.append(vfs->fileSuffix());
+ str.append(_discoveryData->_syncOptions._vfs->fileSuffix());
}
bool ProcessDirectoryJob::hasVirtualFileSuffix(const QString &str) const
return false;
}
errno = 0;
- while (auto dirent = csync_vio_local_readdir(dh, _discoveryData->_syncOptions._vfs)) {
+ while (auto dirent = csync_vio_local_readdir(dh, _discoveryData->_syncOptions._vfs.data())) {
if (dirent->type == ItemTypeSkip)
continue;
LocalInfo i;
bool ProcessDirectoryJob::isVfsWithSuffix() const
{
- auto vfs = _discoveryData->_syncOptions._vfs;
- return vfs && vfs->mode() == Vfs::WithSuffix;
+ return _discoveryData->_syncOptions._vfs->mode() == Vfs::WithSuffix;
}
}
, _queryServer(queryServer)
, _queryLocal(queryLocal)
, _discoveryData(data)
-
{
}
+
void start();
/** Start up to nbJobs, return the number of job started; emit finished() when done */
int processSubJobs(int nbJobs);
void DiscoveryPhase::checkSelectiveSyncNewFolder(const QString &path, RemotePermissions remotePerm,
std::function<void(bool)> callback)
{
- if (_syncOptions._confirmExternalStorage && !_syncOptions._vfs
+ if (_syncOptions._confirmExternalStorage && _syncOptions._vfs->mode() == Vfs::Off
&& remotePerm.hasPermission(RemotePermissions::IsMounted)) {
// external storage.
}
auto limit = _syncOptions._newBigFolderSizeLimit;
- if (limit < 0 || _syncOptions._vfs) {
+ if (limit < 0 || _syncOptions._vfs->mode() != Vfs::Off) {
// no limit, everything is allowed;
return callback(false);
}
_stopwatch.start();
auto &syncOptions = propagator()->syncOptions();
- auto vfs = syncOptions._vfs;
+ auto &vfs = syncOptions._vfs;
// For virtual files just create the file and be done
if (_item->_type == ItemTypeVirtualFileDehydration) {
propagator()->_journal->deleteFileRecord(_item->_file);
QFile::remove(fn);
- if (vfs && vfs->mode() == Vfs::WithSuffix) {
+ if (vfs->mode() == Vfs::WithSuffix) {
// Normally new suffix-virtual files already have the suffix included in the path
// but for dehydrations that isn't the case. Adjust it here.
_item->_file.append(vfs->fileSuffix());
}
}
+ if (vfs->mode() == Vfs::Off && _item->_type == ItemTypeVirtualFile) {
+ qCWarning(lcPropagateDownload) << "ignored virtual file type of" << _item->_file;
+ _item->_type = ItemTypeFile;
+ }
if (_item->_type == ItemTypeVirtualFile) {
auto fn = propagator()->getFilePath(_item->_file);
qCDebug(lcPropagateDownload) << "creating virtual file" << fn;
- ASSERT(vfs);
vfs->createPlaceholder(propagator()->_localDir, _item);
updateMetadata(false);
return;
}
// Make the file a hydrated placeholder if possible
- if (auto vfs = propagator()->syncOptions()._vfs) {
- vfs->convertToPlaceholder(fn, _item);
- }
+ propagator()->syncOptions()._vfs->convertToPlaceholder(fn, _item);
FileSystem::setFileHidden(fn, false);
QString source = propagator()->_remoteFolder + _item->_file;
QString destination = QDir::cleanPath(propagator()->account()->davUrl().path() + propagator()->_remoteFolder + _item->_renameTarget);
- auto vfs = propagator()->syncOptions()._vfs;
- if (vfs && vfs->mode() == Vfs::WithSuffix
+ auto &vfs = propagator()->syncOptions()._vfs;
+ if (vfs->mode() == Vfs::WithSuffix
&& (_item->_type == ItemTypeVirtualFile || _item->_type == ItemTypeVirtualFileDownload)) {
const auto suffix = vfs->fileSuffix();
ASSERT(source.endsWith(suffix) && destination.endsWith(suffix));
_lastLocalDiscoveryStyle = _localDiscoveryStyle;
- if (_syncOptions._vfs && _syncOptions._vfs->mode() == Vfs::WithSuffix) {
- if (_syncOptions._vfs->fileSuffix().isEmpty()) {
- syncError(tr("Using virtual files with suffix, but suffix is not set"));
- finalize(false);
- return;
- }
+ if (_syncOptions._vfs->mode() == Vfs::WithSuffix && _syncOptions._vfs->fileSuffix().isEmpty()) {
+ syncError(tr("Using virtual files with suffix, but suffix is not set"));
+ finalize(false);
+ return;
}
// If needed, make sure we have up to date E2E information before the
return false;
}
-void SyncEngine::wipeVirtualFiles(const QString &localPath, SyncJournalDb &journal, Vfs *vfs)
+void SyncEngine::wipeVirtualFiles(const QString &localPath, SyncJournalDb &journal, Vfs &vfs)
{
qCInfo(lcEngine) << "Wiping virtual files inside" << localPath;
journal.getFilesBelowPath(QByteArray(), [&](const SyncJournalFileRecord &rec) {
// If the local file is a dehydrated placeholder, wipe it too.
// Otherwise leave it to allow the next sync to have a new-new conflict.
QString localFile = localPath + rec._path;
- if (QFile::exists(localFile) && vfs && vfs->isDehydratedPlaceholder(localFile)) {
+ if (QFile::exists(localFile) && vfs.isDehydratedPlaceholder(localFile)) {
qCDebug(lcEngine) << "Removing local dehydrated placeholder" << rec._path;
QFile::remove(localFile);
}
* Particularly useful when switching off vfs mode or switching to a
* different kind of vfs.
*/
- static void wipeVirtualFiles(const QString &localPath, SyncJournalDb &journal, Vfs *vfs);
+ static void wipeVirtualFiles(const QString &localPath, SyncJournalDb &journal, Vfs &vfs);
auto getPropagator() { return _propagator; } // for the test
#include "owncloudlib.h"
#include <QString>
+#include <QSharedPointer>
#include <chrono>
#include "common/vfs.h"
*/
struct SyncOptions
{
+ SyncOptions()
+ : _vfs(new VfsOff)
+ {}
+
/** Maximum size (in Bytes) a folder can have without asking for confirmation.
* -1 means infinite */
qint64 _newBigFolderSizeLimit = -1;
/** If remotely deleted files are needed to move to trash */
bool _moveFilesToTrash = false;
- /** Create a virtual file for new files instead of downloading */
- Vfs *_vfs = nullptr;
+ /** Create a virtual file for new files instead of downloading. May not be null */
+ QSharedPointer<Vfs> _vfs;
/** 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
SyncOptions vfsSyncOptions()
{
SyncOptions options;
- // leak here
- options._vfs = createVfsFromPlugin(Vfs::WithSuffix).release();
+ options._vfs.reset(createVfsFromPlugin(Vfs::WithSuffix).release());
return options;
}
QVERIFY(fakeFolder.currentLocalState().find("A/a1.nextcloud"));
// Switch off new files becoming virtual files
- syncOptions._vfs = nullptr;
+ syncOptions._vfs.reset(new VfsOff);
fakeFolder.syncEngine().setSyncOptions(syncOptions);
// A sync that doesn't do remote discovery will wipe the placeholder, but not redownload
// Now wipe the virtuals
- SyncEngine::wipeVirtualFiles(fakeFolder.localPath(), fakeFolder.syncJournal(), fakeFolder.syncEngine().syncOptions()._vfs);
+ SyncEngine::wipeVirtualFiles(fakeFolder.localPath(), fakeFolder.syncJournal(), *fakeFolder.syncEngine().syncOptions()._vfs);
QVERIFY(!fakeFolder.currentLocalState().find("f1.nextcloud"));
QVERIFY(!fakeFolder.currentLocalState().find("A/a1.nextcloud"));