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

Common: Make recursive FileUtil functions take a maximum recursion

Fixes #1115.

Also improves the performances of DiskArchive’s directory
implementation a lot, simply by not going through the entire tree
instead of just listing the first level files.

Thanks to JayRoxFox for rebasing this on current master!
Emmanuel Gil Peyrot 11 лет назад
Родитель
Сommit
8ab6f26c09
4 измененных файлов с 43 добавлено и 30 удалено
  1. 6 5
      src/citra_qt/game_list.cpp
  2. 1 1
      src/citra_qt/game_list_p.h
  3. 28 20
      src/common/file_util.cpp
  4. 8 4
      src/common/file_util.h

+ 6 - 5
src/citra_qt/game_list.cpp

@@ -118,19 +118,20 @@ void GameList::LoadInterfaceLayout()
     item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder());
 }
 
-void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan)
+void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion)
 {
     const auto callback = [&](unsigned* num_entries_out,
                               const std::string& directory,
-                              const std::string& virtual_name) -> bool {
+                              const std::string& virtual_name,
+                              unsigned int recursion) -> bool {
 
         std::string physical_name = directory + DIR_SEP + virtual_name;
 
         if (stop_processing)
             return false; // Breaks the callback loop.
 
-        if (deep_scan && FileUtil::IsDirectory(physical_name)) {
-            AddFstEntriesToGameList(physical_name, true);
+        if (recursion > 0 && FileUtil::IsDirectory(physical_name)) {
+            AddFstEntriesToGameList(physical_name, recursion - 1);
         } else {
             std::string filename_filename, filename_extension;
             Common::SplitPath(physical_name, nullptr, &filename_filename, &filename_extension);
@@ -169,7 +170,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d
 void GameListWorker::run()
 {
     stop_processing = false;
-    AddFstEntriesToGameList(dir_path.toStdString(), deep_scan);
+    AddFstEntriesToGameList(dir_path.toStdString(), deep_scan ? 256 : 0);
     emit Finished();
 }
 

+ 1 - 1
src/citra_qt/game_list_p.h

@@ -212,5 +212,5 @@ private:
     bool deep_scan;
     std::atomic_bool stop_processing;
 
-    void AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan);
+    void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion = 0);
 };

+ 28 - 20
src/common/file_util.cpp

@@ -434,7 +434,7 @@ bool CreateEmptyFile(const std::string &filename)
 }
 
 
-bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback)
+bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback, unsigned int recursion)
 {
     LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
 
@@ -472,7 +472,7 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
             continue;
 
         unsigned ret_entries = 0;
-        if (!callback(&ret_entries, directory, virtual_name)) {
+        if (!callback(&ret_entries, directory, virtual_name, recursion)) {
             callback_error = true;
             break;
         }
@@ -486,30 +486,34 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
     closedir(dirp);
 #endif
 
-    if (!callback_error) {
-        // num_entries_out is allowed to be specified nullptr, in which case we shouldn't try to set it
-        if (num_entries_out != nullptr)
-            *num_entries_out = found_entries;
-        return true;
-    } else {
+    if (callback_error)
         return false;
-    }
+
+    // num_entries_out is allowed to be specified nullptr, in which case we shouldn't try to set it
+    if (num_entries_out != nullptr)
+        *num_entries_out = found_entries;
+    return true;
 }
 
-unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry)
+unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion)
 {
     const auto callback = [&parent_entry](unsigned* num_entries_out,
                                           const std::string& directory,
-                                          const std::string& virtual_name) -> bool {
+                                          const std::string& virtual_name,
+                                          unsigned int recursion) -> bool {
         FSTEntry entry;
         entry.virtualName = virtual_name;
         entry.physicalName = directory + DIR_SEP + virtual_name;
 
         if (IsDirectory(entry.physicalName)) {
             entry.isDirectory = true;
-            // is a directory, lets go inside
-            entry.size = ScanDirectoryTree(entry.physicalName, entry);
-            *num_entries_out += (int)entry.size;
+            // is a directory, lets go inside if we didn't recurse to often
+            if (recursion > 0) {
+                entry.size = ScanDirectoryTree(entry.physicalName, entry, recursion - 1);
+                *num_entries_out += (int)entry.size;
+            } else {
+                entry.size = 0;
+            }
         } else { // is a file
             entry.isDirectory = false;
             entry.size = GetSize(entry.physicalName);
@@ -522,23 +526,27 @@ unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry)
     };
 
     unsigned num_entries;
-    return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0;
+    return ForeachDirectoryEntry(&num_entries, directory, callback, recursion) ? num_entries : 0;
 }
 
 
-bool DeleteDirRecursively(const std::string &directory)
+bool DeleteDirRecursively(const std::string &directory, unsigned int recursion)
 {
     const static auto callback = [](unsigned* num_entries_out,
                                     const std::string& directory,
-                                    const std::string& virtual_name) -> bool {
+                                    const std::string& virtual_name,
+                                    unsigned int recursion) -> bool {
         std::string new_path = directory + DIR_SEP_CHR + virtual_name;
-        if (IsDirectory(new_path))
-            return DeleteDirRecursively(new_path);
 
+        if (IsDirectory(new_path)) {
+            if (recursion == 0)
+                return false;
+            return DeleteDirRecursively(new_path, recursion - 1);
+        }
         return Delete(new_path);
     };
 
-    if (!ForeachDirectoryEntry(nullptr, directory, callback))
+    if (!ForeachDirectoryEntry(nullptr, directory, callback, recursion))
         return false;
 
     // Delete the outermost directory

+ 8 - 4
src/common/file_util.h

@@ -105,11 +105,13 @@ bool CreateEmptyFile(const std::string &filename);
  * @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null
  * @param directory the path to the enclosing directory
  * @param virtual_name the entry name, without any preceding directory info
+ * @param recursion Number of children directory to read before giving up
  * @return whether handling the entry succeeded
  */
 using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out,
                                                  const std::string& directory,
-                                                 const std::string& virtual_name)>;
+                                                 const std::string& virtual_name,
+                                                 unsigned int recursion)>;
 
 /**
  * Scans a directory, calling the callback for each file/directory contained within.
@@ -117,20 +119,22 @@ using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out,
  * @param num_entries_out assigned by the function with the number of iterated directory entries, can be null
  * @param directory the directory to scan
  * @param callback The callback which will be called for each entry
+ * @param recursion Number of children directories to read before giving up
  * @return whether scanning the directory succeeded
  */
-bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback);
+bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback, unsigned int recursion = 0);
 
 /**
  * Scans the directory tree, storing the results.
  * @param directory the parent directory to start scanning from
  * @param parent_entry FSTEntry where the filesystem tree results will be stored.
+ * @param recursion Number of children directories to read before giving up.
  * @return the total number of files/directories found
  */
-unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry);
+unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion = 0);
 
 // deletes the given directory and anything under it. Returns true on success.
-bool DeleteDirRecursively(const std::string &directory);
+bool DeleteDirRecursively(const std::string &directory, unsigned int recursion = 256);
 
 // Returns the current directory
 std::string GetCurrentDir();