From b6ff58a9d69c034f8c97505a040f47bbe92ab3b7 Mon Sep 17 00:00:00 2001
From: SachinVin <sachinvinayak2000@gmail.com>
Date: Sat, 30 Apr 2022 14:45:15 +0530
Subject: [PATCH] FileUtil, Frontends: Fix updating custom NAND/SDMC path

---
 src/citra/config.cpp                          | 13 ++++++---
 src/citra_qt/configuration/config.cpp         | 26 +++++++++++-------
 .../configuration/configure_storage.cpp       | 22 ++++++++-------
 .../configuration/configure_storage.ui        |  4 +--
 src/common/file_util.cpp                      | 27 ++++++++++++-------
 src/common/file_util.h                        |  4 +++
 src/core/settings.cpp                         |  4 +--
 src/core/settings.h                           |  2 --
 8 files changed, 63 insertions(+), 39 deletions(-)

diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 6f747fcf5..5037c1b41 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -201,10 +201,15 @@ void Config::ReadValues() {
     // Data Storage
     Settings::values.use_virtual_sd =
         sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
-    Settings::values.nand_dir = sdl2_config->GetString(
-        "Data Storage", "nand_directory", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
-    Settings::values.sdmc_dir = sdl2_config->GetString(
-        "Data Storage", "sdmc_directory", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
+
+    const std::string default_nand_dir = FileUtil::GetDefaultUserPath(FileUtil::UserPath::NANDDir);
+    FileUtil::UpdateUserPath(
+        FileUtil::UserPath::NANDDir,
+        sdl2_config->GetString("Data Storage", "nand_directory", default_nand_dir));
+    const std::string default_sdmc_dir = FileUtil::GetDefaultUserPath(FileUtil::UserPath::SDMCDir);
+    FileUtil::UpdateUserPath(
+        FileUtil::UserPath::SDMCDir,
+        sdl2_config->GetString("Data Storage", "sdmc_directory", default_sdmc_dir));
 
     // System
     Settings::values.is_new_3ds = sdl2_config->GetBoolean("System", "is_new_3ds", true);
diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp
index 28612bbd0..770a7fe30 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/citra_qt/configuration/config.cpp
@@ -302,17 +302,23 @@ void Config::ReadDataStorageValues() {
     qt_config->beginGroup(QStringLiteral("Data Storage"));
 
     Settings::values.use_virtual_sd = ReadSetting(QStringLiteral("use_virtual_sd"), true).toBool();
-    std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
-    Settings::values.nand_dir =
-        ReadSetting(QStringLiteral("nand_directory"), QString::fromStdString(nand_dir))
+
+    const std::string nand_dir =
+        ReadSetting(
+            QStringLiteral("nand_directory"),
+            QString::fromStdString(FileUtil::GetDefaultUserPath(FileUtil::UserPath::NANDDir)))
             .toString()
             .toStdString();
-    std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
-    Settings::values.sdmc_dir =
-        ReadSetting(QStringLiteral("sdmc_directory"), QString::fromStdString(sdmc_dir))
+    const std::string sdmc_dir =
+        ReadSetting(
+            QStringLiteral("sdmc_directory"),
+            QString::fromStdString(FileUtil::GetDefaultUserPath(FileUtil::UserPath::SDMCDir)))
             .toString()
             .toStdString();
 
+    FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir, nand_dir);
+    FileUtil::UpdateUserPath(FileUtil::UserPath::SDMCDir, sdmc_dir);
+
     qt_config->endGroup();
 }
 
@@ -863,11 +869,11 @@ void Config::SaveDataStorageValues() {
 
     WriteSetting(QStringLiteral("use_virtual_sd"), Settings::values.use_virtual_sd, true);
     WriteSetting(QStringLiteral("nand_directory"),
-                 QString::fromStdString(Settings::values.nand_dir),
-                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
+                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)),
+                 QString::fromStdString(FileUtil::GetDefaultUserPath(FileUtil::UserPath::NANDDir)));
     WriteSetting(QStringLiteral("sdmc_directory"),
-                 QString::fromStdString(Settings::values.sdmc_dir),
-                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
+                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)),
+                 QString::fromStdString(FileUtil::GetDefaultUserPath(FileUtil::UserPath::SDMCDir)));
 
     qt_config->endGroup();
 }
diff --git a/src/citra_qt/configuration/configure_storage.cpp b/src/citra_qt/configuration/configure_storage.cpp
index 62e299a90..dcc414630 100644
--- a/src/citra_qt/configuration/configure_storage.cpp
+++ b/src/citra_qt/configuration/configure_storage.cpp
@@ -16,31 +16,33 @@ ConfigureStorage::ConfigureStorage(QWidget* parent)
     SetConfiguration();
 
     connect(ui->open_nand_dir, &QPushButton::clicked, []() {
-        QString path = QString::fromStdString(Settings::values.nand_dir);
+        QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
         QDesktopServices::openUrl(QUrl::fromLocalFile(path));
     });
 
     connect(ui->change_nand_dir, &QPushButton::clicked, this, [this]() {
         const QString dir_path = QFileDialog::getExistingDirectory(
-            this, tr("Select NAND Directory"), QString::fromStdString(Settings::values.nand_dir),
+            this, tr("Select NAND Directory"),
+            QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)),
             QFileDialog::ShowDirsOnly);
         if (!dir_path.isEmpty()) {
-            Settings::values.nand_dir = dir_path.toStdString();
+            FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir, dir_path.toStdString());
             SetConfiguration();
         }
     });
 
     connect(ui->open_sdmc_dir, &QPushButton::clicked, []() {
-        QString path = QString::fromStdString(Settings::values.sdmc_dir);
+        QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
         QDesktopServices::openUrl(QUrl::fromLocalFile(path));
     });
 
     connect(ui->change_sdmc_dir, &QPushButton::clicked, this, [this]() {
         const QString dir_path = QFileDialog::getExistingDirectory(
-            this, tr("Select SDMC Directory"), QString::fromStdString(Settings::values.sdmc_dir),
+            this, tr("Select SDMC Directory"),
+            QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)),
             QFileDialog::ShowDirsOnly);
         if (!dir_path.isEmpty()) {
-            Settings::values.sdmc_dir = dir_path.toStdString();
+            FileUtil::UpdateUserPath(FileUtil::UserPath::SDMCDir, dir_path.toStdString());
             SetConfiguration();
         }
     });
@@ -55,14 +57,14 @@ ConfigureStorage::~ConfigureStorage() = default;
 
 void ConfigureStorage::SetConfiguration() {
     ui->nand_group->setVisible(Settings::values.use_virtual_sd);
-    QString nand_path = QString::fromStdString(Settings::values.nand_dir);
+    QString nand_path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
     ui->nand_dir_path->setText(nand_path);
-    ui->open_nand_dir->setEnabled(!Settings::values.nand_dir.empty());
+    ui->open_nand_dir->setEnabled(!nand_path.isEmpty());
 
     ui->sdmc_group->setVisible(Settings::values.use_virtual_sd);
-    QString sdmc_path = QString::fromStdString(Settings::values.sdmc_dir);
+    QString sdmc_path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
     ui->sdmc_dir_path->setText(sdmc_path);
-    ui->open_sdmc_dir->setEnabled(!Settings::values.sdmc_dir.empty());
+    ui->open_sdmc_dir->setEnabled(!sdmc_path.isEmpty());
 
     ui->toggle_virtual_sd->setChecked(Settings::values.use_virtual_sd);
 
diff --git a/src/citra_qt/configuration/configure_storage.ui b/src/citra_qt/configuration/configure_storage.ui
index c6f72dd5d..5571d200f 100644
--- a/src/citra_qt/configuration/configure_storage.ui
+++ b/src/citra_qt/configuration/configure_storage.ui
@@ -69,7 +69,7 @@
              <item>
               <widget class="QLabel" name="label_4">
                <property name="text">
-                <string>NOTE: this does not move the contents of the previous directory to the new one</string>
+                <string>NOTE: This does not move the contents of the previous directory to the new one.</string>
                </property>
               </widget>
              </item>
@@ -134,7 +134,7 @@
              <item>
               <widget class="QLabel" name="label_3">
                <property name="text">
-                <string>NOTE: this does not move the contents of the previous directory to the new one</string>
+                <string>NOTE: This does not move the contents of the previous directory to the new one.</string>
                </property>
               </widget>
              </item>
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 7b360967b..436d94406 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -12,7 +12,6 @@
 #include "common/common_paths.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
-#include "core/settings.h"
 
 #ifdef _WIN32
 #include <windows.h>
@@ -674,7 +673,8 @@ std::string GetSysDirectory() {
 
 namespace {
 std::unordered_map<UserPath, std::string> g_paths;
-}
+std::unordered_map<UserPath, std::string> g_default_paths;
+} // namespace
 
 void SetUserPath(const std::string& path) {
     std::string& user_path = g_paths[UserPath::UserDir];
@@ -718,12 +718,8 @@ void SetUserPath(const std::string& path) {
 #endif
     }
 
-    g_paths.emplace(UserPath::SDMCDir, !Settings::values.sdmc_dir.empty()
-                                           ? Settings::values.sdmc_dir
-                                           : user_path + SDMC_DIR DIR_SEP);
-    g_paths.emplace(UserPath::NANDDir, !Settings::values.nand_dir.empty()
-                                           ? Settings::values.nand_dir
-                                           : user_path + NAND_DIR DIR_SEP);
+    g_paths.emplace(UserPath::SDMCDir, user_path + SDMC_DIR DIR_SEP);
+    g_paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
     g_paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
     // TODO: Put the logs in a better location for each OS
     g_paths.emplace(UserPath::LogDir, user_path + LOG_DIR DIR_SEP);
@@ -733,6 +729,7 @@ void SetUserPath(const std::string& path) {
     g_paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
     g_paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
     g_paths.emplace(UserPath::StatesDir, user_path + STATES_DIR DIR_SEP);
+    g_default_paths = g_paths;
 }
 
 std::string g_currentRomPath{};
@@ -769,8 +766,20 @@ const std::string& GetUserPath(UserPath path) {
     return g_paths[path];
 }
 
+const std::string& GetDefaultUserPath(UserPath path) {
+    // Set up all paths and files on the first run
+    if (g_default_paths.empty())
+        SetUserPath();
+    return g_default_paths[path];
+}
+
 const void UpdateUserPath(UserPath path, const std::string& filename) {
-    g_paths[path] = filename + DIR_SEP;
+    if (!FileUtil::IsDirectory(filename)) {
+        LOG_ERROR(Common_Filesystem, "Path is not a directory. UserPath: {}  filename: {}", path,
+                  filename);
+        return;
+    }
+    g_paths[path] = SanitizePath(filename) + DIR_SEP;
 }
 
 std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str) {
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 0f0e862c3..cdd55b665 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -186,6 +186,10 @@ void SetCurrentRomPath(const std::string& path);
 // directory. To be used in "multi-user" mode (that is, installed).
 [[nodiscard]] const std::string& GetUserPath(UserPath path);
 
+// Returns a pointer to a string with the default Citra data dir in the user's home
+// directory.
+[[nodiscard]] const std::string& GetDefaultUserPath(UserPath path);
+
 // Update the Global Path with the new value
 const void UpdateUserPath(UserPath path, const std::string& filename);
 
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index a63f23b07..c5c1b6155 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -120,8 +120,8 @@ void LogSettings() {
     log_setting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]);
     log_setting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]);
     log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
-    log_setting("DataStorage_SdmcDir", values.sdmc_dir);
-    log_setting("DataStorage_NandDir", values.nand_dir);
+    log_setting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
+    log_setting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
     log_setting("System_IsNew3ds", values.is_new_3ds);
     log_setting("System_RegionValue", values.region_value);
     log_setting("Debugging_UseGdbstub", values.use_gdbstub);
diff --git a/src/core/settings.h b/src/core/settings.h
index 6030c0868..e7339275c 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -155,8 +155,6 @@ struct Values {
 
     // Data Storage
     bool use_virtual_sd;
-    std::string nand_dir;
-    std::string sdmc_dir;
 
     // System
     int region_value;