From: Olivier Goffart Date: Mon, 28 May 2018 12:49:02 +0000 (+0200) Subject: Virtual Files: Allow to download a folder recursively from the socket API X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~578 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4ee244190be9bab1b79ef5d9c46eb29125d7b39f;p=nextcloud-desktop.git Virtual Files: Allow to download a folder recursively from the socket API Issue: #6466 --- diff --git a/src/common/syncjournaldb.cpp b/src/common/syncjournaldb.cpp index 41cf3e0bf..e61ef0970 100644 --- a/src/common/syncjournaldb.cpp +++ b/src/common/syncjournaldb.cpp @@ -2062,6 +2062,25 @@ void SyncJournalDb::clearFileTable() query.exec(); } +void SyncJournalDb::markVirtualFileForDownloadRecursively(const QByteArray &path) +{ + QMutexLocker lock(&_mutex); + if (!checkConnect()) + return; + + static_assert(ItemTypeVirtualFile == 4 && ItemTypeVirtualFileDownload == 5, ""); + SqlQuery query("UPDATE metadata SET type=5 WHERE " IS_PREFIX_PATH_OF("?1", "path") " AND type=4;", _db); + query.bindValue(1, path); + query.exec(); + + // We also must make sure we do not read the files from the database (same logic as in avoidReadFromDbOnNextSync) + // This includes all the parents up to the root, but also all the directory within the selected dir. + static_assert(ItemTypeDirectory == 2, ""); + query.prepare("UPDATE metadata SET md5='_invalid_' WHERE (" IS_PREFIX_PATH_OF("?1", "path") " OR " IS_PREFIX_PATH_OR_EQUAL("path", "?1") ") AND type == 2;"); + query.bindValue(1, path); + query.exec(); +} + void SyncJournalDb::commit(const QString &context, bool startTrans) { QMutexLocker lock(&_mutex); diff --git a/src/common/syncjournaldb.h b/src/common/syncjournaldb.h index de93bdc5e..f9992a71e 100644 --- a/src/common/syncjournaldb.h +++ b/src/common/syncjournaldb.h @@ -241,6 +241,12 @@ public: */ void clearFileTable(); + /** + * Set the 'ItemTypeVirtualFileDownload' to all the files that have the ItemTypeVirtualFile flag + * within the directory specified path path + */ + void markVirtualFileForDownloadRecursively(const QByteArray &path); + private: int getFileRecordCount(); bool updateDatabaseStructure(); diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index 0e24fffdc..56fa56401 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -532,11 +532,16 @@ void Folder::downloadVirtualFile(const QString &_relativepath) _journal.getFileRecord(relativepath, &record); if (!record.isValid()) return; - record._type = ItemTypeVirtualFileDownload; - _journal.setFileRecord(record); - - // Make sure we go over that file during the discovery - _journal.avoidReadFromDbOnNextSync(relativepath); + if (record._type == ItemTypeVirtualFile) { + record._type = ItemTypeVirtualFileDownload; + _journal.setFileRecord(record); + // Make sure we go over that file during the discovery + _journal.avoidReadFromDbOnNextSync(relativepath); + } else if (record._type == ItemTypeDirectory) { + _journal.markVirtualFileForDownloadRecursively(relativepath); + } else { + qCWarning(lcFolder) << "Invalid existing record " << record._type << " for file " << _relativepath; + } // Schedule a sync (Folder man will start the sync in a few ms) slotScheduleThisFolder(); diff --git a/src/gui/folder.h b/src/gui/folder.h index e1d642f3e..46d3499e3 100644 --- a/src/gui/folder.h +++ b/src/gui/folder.h @@ -236,6 +236,9 @@ public: */ void registerFolderWatcher(); + /** new files are downloaded as virtual files */ + bool useVirtualFiles() { return _definition.useVirtualFiles; } + signals: void syncStateChange(); void syncStarted(); diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index c1ccdc2ea..3f222e949 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -692,7 +692,7 @@ void SocketApi::command_DOWNLOAD_VIRTUAL_FILE(const QString &filesArg, SocketLis auto suffix = QStringLiteral(APPLICATION_DOTVIRTUALFILE_SUFFIX); for (const auto &file : files) { - if (!file.endsWith(suffix)) + if (!file.endsWith(suffix) && !QFileInfo(file).isDir()) continue; auto folder = FolderMan::instance()->folderForPath(file); if (folder) { @@ -980,7 +980,7 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe auto virtualFileSuffix = QStringLiteral(APPLICATION_DOTVIRTUALFILE_SUFFIX); bool hasVirtualFile = false; for (const auto &file : files) { - if (file.endsWith(virtualFileSuffix)) + if (file.endsWith(virtualFileSuffix) || (syncFolder->useVirtualFiles() && QFileInfo(file).isDir())) hasVirtualFile = true; } if (hasVirtualFile) diff --git a/test/testsyncvirtualfiles.cpp b/test/testsyncvirtualfiles.cpp index 0bcd33c51..db677a306 100644 --- a/test/testsyncvirtualfiles.cpp +++ b/test/testsyncvirtualfiles.cpp @@ -485,6 +485,105 @@ private slots: QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); QVERIFY(!dbRecord(fakeFolder, "A/a1.owncloud").isValid()); } + + void testDownloadRecursive() + { + FakeFolder fakeFolder{ FileInfo() }; + SyncOptions syncOptions; + syncOptions._newFilesAreVirtual = true; + fakeFolder.syncEngine().setSyncOptions(syncOptions); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + // Create a virtual file for remote files + fakeFolder.remoteModifier().mkdir("A"); + fakeFolder.remoteModifier().mkdir("A/Sub"); + fakeFolder.remoteModifier().mkdir("A/Sub/SubSub"); + fakeFolder.remoteModifier().mkdir("A/Sub2"); + fakeFolder.remoteModifier().mkdir("B"); + fakeFolder.remoteModifier().mkdir("B/Sub"); + fakeFolder.remoteModifier().insert("A/a1"); + fakeFolder.remoteModifier().insert("A/a2"); + fakeFolder.remoteModifier().insert("A/Sub/a3"); + fakeFolder.remoteModifier().insert("A/Sub/a4"); + fakeFolder.remoteModifier().insert("A/Sub/SubSub/a5"); + fakeFolder.remoteModifier().insert("A/Sub2/a6"); + fakeFolder.remoteModifier().insert("B/b1"); + fakeFolder.remoteModifier().insert("B/Sub/b2"); + QVERIFY(fakeFolder.syncOnce()); + QVERIFY(fakeFolder.currentLocalState().find("A/a1.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/a2.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/a3.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/a4.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/SubSub/a5.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub2/a6.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("B/b1.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("B/Sub/b2.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/a1")); + QVERIFY(!fakeFolder.currentLocalState().find("A/a2")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/a3")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/a4")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/SubSub/a5")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub2/a6")); + QVERIFY(!fakeFolder.currentLocalState().find("B/b1")); + QVERIFY(!fakeFolder.currentLocalState().find("B/Sub/b2")); + + + // Download All file in the directory A/Sub + // (as in Folder::downloadVirtualFile) + fakeFolder.syncJournal().markVirtualFileForDownloadRecursively("A/Sub"); + + QVERIFY(fakeFolder.syncOnce()); + QVERIFY(fakeFolder.currentLocalState().find("A/a1.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/a2.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/a3.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/a4.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/SubSub/a5.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub2/a6.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("B/b1.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("B/Sub/b2.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/a1")); + QVERIFY(!fakeFolder.currentLocalState().find("A/a2")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/a3")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/a4")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/SubSub/a5")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub2/a6")); + QVERIFY(!fakeFolder.currentLocalState().find("B/b1")); + QVERIFY(!fakeFolder.currentLocalState().find("B/Sub/b2")); + + // Add a file in a subfolder that was downloaded + // Currently, this continue to add it as a virtual file. + fakeFolder.remoteModifier().insert("A/Sub/SubSub/a7"); + QVERIFY(fakeFolder.syncOnce()); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/SubSub/a7.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/SubSub/a7")); + + // Now download all files in "A" + fakeFolder.syncJournal().markVirtualFileForDownloadRecursively("A"); + QVERIFY(fakeFolder.syncOnce()); + QVERIFY(!fakeFolder.currentLocalState().find("A/a1.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/a2.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/a3.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/a4.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/SubSub/a5.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub2/a6.owncloud")); + QVERIFY(!fakeFolder.currentLocalState().find("A/Sub/SubSub/a7.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("B/b1.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("B/Sub/b2.owncloud")); + QVERIFY(fakeFolder.currentLocalState().find("A/a1")); + QVERIFY(fakeFolder.currentLocalState().find("A/a2")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/a3")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/a4")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/SubSub/a5")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub2/a6")); + QVERIFY(fakeFolder.currentLocalState().find("A/Sub/SubSub/a7")); + QVERIFY(!fakeFolder.currentLocalState().find("B/b1")); + QVERIFY(!fakeFolder.currentLocalState().find("B/Sub/b2")); + + // Now download remaining files in "B" + fakeFolder.syncJournal().markVirtualFileForDownloadRecursively("B"); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + } }; QTEST_GUILESS_MAIN(TestSyncVirtualFiles)