Skip to content

Commit 8f5bcb0

Browse files
authored
file_sys: Consolidate separate update directory handling. (#2041)
1 parent af8c748 commit 8f5bcb0

File tree

5 files changed

+61
-107
lines changed

5 files changed

+61
-107
lines changed

src/core/file_sys/fs.cpp

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ void MntPoints::UnmountAll() {
4040
m_mnt_pairs.clear();
4141
}
4242

43-
std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_read_only) {
43+
std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_read_only,
44+
bool force_base_path) {
4445
// Evil games like Turok2 pass double slashes e.g /app0//game.kpf
4546
std::string corrected_path(path);
4647
size_t pos = corrected_path.find("//");
@@ -72,7 +73,7 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
7273
patch_path /= rel_path;
7374

7475
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&
75-
std::filesystem::exists(patch_path)) {
76+
!force_base_path && std::filesystem::exists(patch_path)) {
7677
return patch_path;
7778
}
7879

@@ -132,8 +133,10 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
132133
return std::optional<std::filesystem::path>(current_path);
133134
};
134135

135-
if (const auto path = search(patch_path)) {
136-
return *path;
136+
if (!force_base_path) {
137+
if (const auto path = search(patch_path)) {
138+
return *path;
139+
}
137140
}
138141
if (const auto path = search(host_path)) {
139142
return *path;
@@ -144,6 +147,39 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
144147
return host_path;
145148
}
146149

150+
// TODO: Does not handle mount points inside mount points.
151+
void MntPoints::IterateDirectory(std::string_view guest_directory,
152+
const IterateDirectoryCallback& callback) {
153+
const auto base_path = GetHostPath(guest_directory, nullptr, true);
154+
const auto patch_path = GetHostPath(guest_directory, nullptr, false);
155+
// Only need to consider patch path if it exists and does not resolve to the same as base.
156+
const auto apply_patch = base_path != patch_path && std::filesystem::exists(patch_path);
157+
158+
// Pass 1: Any files that existed in the base directory, using patch directory if needed.
159+
if (std::filesystem::exists(base_path)) {
160+
for (const auto& entry : std::filesystem::directory_iterator(base_path)) {
161+
if (apply_patch) {
162+
const auto patch_entry_path = patch_path / entry.path().filename();
163+
if (std::filesystem::exists(patch_entry_path)) {
164+
callback(patch_entry_path, !std::filesystem::is_directory(patch_entry_path));
165+
continue;
166+
}
167+
}
168+
callback(entry.path(), !entry.is_directory());
169+
}
170+
}
171+
172+
// Pass 2: Any files that exist only in the patch directory.
173+
if (apply_patch) {
174+
for (const auto& entry : std::filesystem::directory_iterator(patch_path)) {
175+
const auto base_entry_path = base_path / entry.path().filename();
176+
if (!std::filesystem::exists(base_entry_path)) {
177+
callback(entry.path(), !entry.is_directory());
178+
}
179+
}
180+
}
181+
}
182+
147183
int HandleTable::CreateHandle() {
148184
std::scoped_lock lock{m_mutex};
149185

src/core/file_sys/fs.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ class MntPoints {
3636
void UnmountAll();
3737

3838
std::filesystem::path GetHostPath(std::string_view guest_directory,
39-
bool* is_read_only = nullptr);
39+
bool* is_read_only = nullptr, bool force_base_path = false);
40+
using IterateDirectoryCallback =
41+
std::function<void(const std::filesystem::path& host_path, bool is_file)>;
42+
void IterateDirectory(std::string_view guest_directory,
43+
const IterateDirectoryCallback& callback);
4044

4145
const MntPair* GetMountFromHostPath(const std::string& host_path) {
4246
std::scoped_lock lock{m_mutex};

src/core/libraries/kernel/file_system.cpp

Lines changed: 8 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,6 @@ static std::map<std::string, FactoryDevice> available_device = {
4646

4747
namespace Libraries::Kernel {
4848

49-
auto GetDirectoryEntries(const std::filesystem::path& path) {
50-
std::vector<Core::FileSys::DirEntry> files;
51-
for (const auto& entry : std::filesystem::directory_iterator(path)) {
52-
auto& dir_entry = files.emplace_back();
53-
dir_entry.name = entry.path().filename().string();
54-
dir_entry.isFile = !std::filesystem::is_directory(entry.path().string());
55-
}
56-
57-
return files;
58-
}
59-
6049
int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
6150
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", raw_path, flags, mode);
6251
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
@@ -115,7 +104,12 @@ int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
115104
if (create) {
116105
return handle; // dir already exists
117106
} else {
118-
file->dirents = GetDirectoryEntries(file->m_host_name);
107+
mnt->IterateDirectory(file->m_guest_name,
108+
[&file](const auto& ent_path, const auto ent_is_file) {
109+
auto& dir_entry = file->dirents.emplace_back();
110+
dir_entry.name = ent_path.filename().string();
111+
dir_entry.isFile = ent_is_file;
112+
});
119113
file->dirents_index = 0;
120114
}
121115
}
@@ -695,66 +689,12 @@ static int GetDents(int fd, char* buf, int nbytes, s64* basep) {
695689
return sizeof(OrbisKernelDirent);
696690
}
697691

698-
static int HandleSeparateUpdateDents(int fd, char* buf, int nbytes, s64* basep) {
699-
int dir_entries = 0;
700-
701-
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
702-
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
703-
auto* file = h->GetFile(fd);
704-
auto update_dir_name = std::string{fmt::UTF(file->m_host_name.u8string()).data};
705-
auto mount = mnt->GetMountFromHostPath(update_dir_name);
706-
auto suffix = std::string{fmt::UTF(mount->host_path.u8string()).data};
707-
708-
size_t pos = update_dir_name.find("-UPDATE");
709-
if (pos != std::string::npos) {
710-
update_dir_name.erase(pos, 7);
711-
auto guest_name = mount->mount + "/" + update_dir_name.substr(suffix.size() + 1);
712-
int descriptor;
713-
714-
auto existent_folder = h->GetFile(update_dir_name);
715-
if (!existent_folder) {
716-
u32 handle = h->CreateHandle();
717-
auto* new_file = h->GetFile(handle);
718-
new_file->type = Core::FileSys::FileType::Directory;
719-
new_file->m_guest_name = guest_name;
720-
new_file->m_host_name = update_dir_name;
721-
if (!std::filesystem::is_directory(new_file->m_host_name)) {
722-
h->DeleteHandle(handle);
723-
return dir_entries;
724-
} else {
725-
new_file->dirents = GetDirectoryEntries(new_file->m_host_name);
726-
new_file->dirents_index = 0;
727-
}
728-
new_file->is_opened = true;
729-
descriptor = h->GetFileDescriptor(new_file);
730-
} else {
731-
descriptor = h->GetFileDescriptor(existent_folder);
732-
}
733-
734-
dir_entries = GetDents(descriptor, buf, nbytes, basep);
735-
if (dir_entries == ORBIS_OK && existent_folder) {
736-
existent_folder->dirents_index = 0;
737-
file->dirents_index = 0;
738-
}
739-
}
740-
741-
return dir_entries;
742-
}
743-
744692
int PS4_SYSV_ABI sceKernelGetdents(int fd, char* buf, int nbytes) {
745-
int a = GetDents(fd, buf, nbytes, nullptr);
746-
if (a == ORBIS_OK) {
747-
return HandleSeparateUpdateDents(fd, buf, nbytes, nullptr);
748-
}
749-
return a;
693+
return GetDents(fd, buf, nbytes, nullptr);
750694
}
751695

752696
int PS4_SYSV_ABI sceKernelGetdirentries(int fd, char* buf, int nbytes, s64* basep) {
753-
int a = GetDents(fd, buf, nbytes, basep);
754-
if (a == ORBIS_OK) {
755-
return HandleSeparateUpdateDents(fd, buf, nbytes, basep);
756-
}
757-
return a;
697+
return GetDents(fd, buf, nbytes, basep);
758698
}
759699

760700
s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) {

src/emulator.cpp

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -217,41 +217,15 @@ void Emulator::Run(const std::filesystem::path& file) {
217217
linker->LoadModule(eboot_path);
218218

219219
// check if we have system modules to load
220-
LoadSystemModules(eboot_path, game_info.game_serial);
220+
LoadSystemModules(game_info.game_serial);
221221

222222
// Load all prx from game's sce_module folder
223-
std::vector<std::filesystem::path> modules_to_load;
224-
std::filesystem::path game_module_folder = file.parent_path() / "sce_module";
225-
if (std::filesystem::is_directory(game_module_folder)) {
226-
for (const auto& entry : std::filesystem::directory_iterator(game_module_folder)) {
227-
if (entry.is_regular_file()) {
228-
modules_to_load.push_back(entry.path());
229-
}
223+
mnt->IterateDirectory("/app0/sce_module", [this](const auto& path, const auto is_file) {
224+
if (is_file) {
225+
LOG_INFO(Loader, "Loading {}", fmt::UTF(path.u8string()));
226+
linker->LoadModule(path);
230227
}
231-
}
232-
233-
// Load all prx from separate update's sce_module folder
234-
std::filesystem::path game_patch_folder = game_folder;
235-
game_patch_folder += "-UPDATE";
236-
std::filesystem::path update_module_folder = game_patch_folder / "sce_module";
237-
if (std::filesystem::is_directory(update_module_folder)) {
238-
for (const auto& entry : std::filesystem::directory_iterator(update_module_folder)) {
239-
auto it = std::find_if(modules_to_load.begin(), modules_to_load.end(),
240-
[&entry](const std::filesystem::path& p) {
241-
return p.filename() == entry.path().filename();
242-
});
243-
if (it != modules_to_load.end()) {
244-
*it = entry.path();
245-
} else {
246-
modules_to_load.push_back(entry.path());
247-
}
248-
}
249-
}
250-
251-
for (const auto& module_path : modules_to_load) {
252-
LOG_INFO(Loader, "Loading {}", fmt::UTF(module_path.u8string()));
253-
linker->LoadModule(module_path);
254-
}
228+
});
255229

256230
#ifdef ENABLE_DISCORD_RPC
257231
// Discord RPC
@@ -278,7 +252,7 @@ void Emulator::Run(const std::filesystem::path& file) {
278252
std::exit(0);
279253
}
280254

281-
void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string game_serial) {
255+
void Emulator::LoadSystemModules(const std::string& game_serial) {
282256
constexpr std::array<SysModules, 11> ModulesToLoad{
283257
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
284258
{"libSceUlt.sprx", nullptr},

src/emulator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Emulator {
2929
void UpdatePlayTime(const std::string& serial);
3030

3131
private:
32-
void LoadSystemModules(const std::filesystem::path& file, std::string game_serial);
32+
void LoadSystemModules(const std::string& game_serial);
3333

3434
Core::MemoryManager* memory;
3535
Input::GameController* controller;

0 commit comments

Comments
 (0)