Просмотр исходного кода

Virtual Files: Allow to download a folder recursively from the socket API

Issue: #6466
Olivier Goffart 7 лет назад
Родитель
Сommit
4ee244190b

+ 19 - 0
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);

+ 6 - 0
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();

+ 10 - 5
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();

+ 3 - 0
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();

+ 2 - 2
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)

+ 99 - 0
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)