Skip to content

Commit

Permalink
Emulation: Fix boot path resolving
Browse files Browse the repository at this point in the history
* Fix /dev_flash executables path arg. (/host_root is wrong for it)
* Fix usage of /host_root for homebrew applications when it is not mounted, use /app_home.
* Fix path source detection. (don't get fooled by path slashes repetitions and '\' on Windows)
* Fix fs::escape_path for comparisons. (inserted NTS character at the end due to a bug, always not include delimiter at the end)
  • Loading branch information
elad335 committed Apr 6, 2021
1 parent 02febd3 commit 30f720b
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 10 deletions.
4 changes: 2 additions & 2 deletions Utilities/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1801,9 +1801,9 @@ std::string fs::escape_path(std::string_view path)
}
}

if (j != umax && (real[j] == delim[0] || real[j] == delim[1])) j--; // Do not include a delmiter at the end
if (j >= 1u && (real[j - 1] == delim[0] || real[j - 1] == delim[1])) j--; // Do not include a delmiter at the end

real.resize(j + 1);
real.resize(j);
return real;
}

Expand Down
45 changes: 38 additions & 7 deletions rpcs3/Emu/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1266,15 +1266,23 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
return game_boot_result::no_errors;
}

// Check if path is inside the specified directory
auto is_path_inside_path = [](std::string_view path, std::string_view dir)
{
return (fs::escape_path(path) + '/').starts_with(fs::escape_path(dir) + '/');
};

// Detect boot location
constexpr usz game_dir_size = 8; // size of PS3_GAME and PS3_GMXX
const std::string hdd0_game = vfs::get("/dev_hdd0/game/");
const std::string hdd0_disc = vfs::get("/dev_hdd0/disc/");
const bool from_hdd0_game = m_path.starts_with(hdd0_game);
const bool from_hdd0_game = is_path_inside_path(m_path, hdd0_game);
const bool from_dev_flash = is_path_inside_path(m_path, g_cfg.vfs.get_dev_flash());

#ifdef _WIN32
// m_path might be passed from command line with differences in uppercase/lowercase on windows.
if (!from_hdd0_game && fmt::to_lower(m_path).starts_with(fmt::to_lower(hdd0_game)))
if ((!from_hdd0_game && is_path_inside_path(fmt::to_lower(m_path), fmt::to_lower(hdd0_game))) ||
(!from_dev_flash && is_path_inside_path(fmt::to_lower(m_path), fmt::to_lower(g_cfg.vfs.get_dev_flash()))))
{
// Let's just abort to prevent errors down the line.
sys_log.error("The boot path seems to contain incorrectly cased characters. Please adjust the path and try again.");
Expand Down Expand Up @@ -1313,7 +1321,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
bdvd_dir = sfb_dir + "/";

// Find game dir
if (const std::string main_dir_name = main_dir.substr(main_dir.find_last_of("/\\") + 1);
if (const std::string main_dir_name = main_dir.substr(main_dir.find_last_of(fs::delim) + 1);
main_dir_name.size() == game_dir_size)
{
m_game_dir = main_dir_name;
Expand Down Expand Up @@ -1638,31 +1646,54 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool

if (argv[0].empty())
{
auto unescape = [](std::string_view path)
{
// Unescape from host FS
std::vector<std::string> escaped = fmt::split(path, {std::string_view{&fs::delim[0], 1}, std::string_view{&fs::delim[1], 1}});
std::vector<std::string> result;
for (auto& sv : escaped)
result.emplace_back(vfs::unescape(sv));

return fmt::merge(result, "/");
};

if (from_hdd0_game && m_cat == "DG")
{
argv[0] = "/dev_bdvd/PS3_GAME/" + m_path.substr(hdd0_game.size() + 10);
argv[0] = "/dev_bdvd/PS3_GAME/" + unescape(m_path.substr(hdd0_game.size() + 10));
m_dir = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size(), 10);
sys_log.notice("Disc path: %s", m_dir);
}
else if (from_hdd0_game)
{
argv[0] = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size());
argv[0] = "/dev_hdd0/game/" + unescape(m_path.substr(hdd0_game.size()));
m_dir = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size(), 10);
sys_log.notice("Boot path: %s", m_dir);
}
else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{
// Disc games are on /dev_bdvd/
const usz pos = m_path.rfind(m_game_dir);
argv[0] = "/dev_bdvd/PS3_GAME/" + m_path.substr(pos + game_dir_size + 1);
argv[0] = "/dev_bdvd/PS3_GAME/" + unescape(m_path.substr(pos + game_dir_size + 1));
m_dir = "/dev_bdvd/PS3_GAME/";
}
else
else if (from_dev_flash)
{
// Firmware executables
argv[0] = "/dev_flash" + fs::escape_path(m_path).substr(fs::escape_path(g_cfg.vfs.get_dev_flash()).size());
m_dir = fs::get_parent_dir(argv[0]) + '/';
}
else if (g_cfg.vfs.host_root)
{
// For homebrew
argv[0] = "/host_root/" + m_path;
m_dir = "/host_root/" + elf_dir + '/';
}
else
{
// Use /app_home if /host_root is disabled
argv[0] = "/app_home/" + m_path.substr(m_path.find_last_of(fs::delim) + 1);
m_dir = "/app_home/";
}

sys_log.notice("Elf path: %s", argv[0]);
}
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/VFS.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "IdManager.h"
#include "System.h"
#include "VFS.h"
Expand Down

0 comments on commit 30f720b

Please sign in to comment.