core/fs: allow to mount path as read-only

This commit is contained in:
Vinicius Rangel 2024-09-07 02:43:28 -03:00
parent 820382a3e7
commit 5e05fecdd0
No known key found for this signature in database
GPG key ID: A5B154D904B761D9
3 changed files with 42 additions and 10 deletions

View file

@ -9,9 +9,10 @@ namespace Core::FileSys {
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder) {
void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder,
bool read_only) {
std::scoped_lock lock{m_mutex};
m_mnt_pairs.emplace_back(host_folder, guest_folder);
m_mnt_pairs.emplace_back(host_folder, guest_folder, read_only);
}
void MntPoints::Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder) {
@ -26,7 +27,7 @@ void MntPoints::UnmountAll() {
m_mnt_pairs.clear();
}
std::filesystem::path MntPoints::GetHostPath(std::string_view guest_directory) {
std::filesystem::path MntPoints::GetHostPath(std::string_view guest_directory, bool* is_read_only) {
// Evil games like Turok2 pass double slashes e.g /app0//game.kpf
std::string corrected_path(guest_directory);
size_t pos = corrected_path.find("//");
@ -40,6 +41,10 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view guest_directory) {
return "";
}
if (is_read_only) {
*is_read_only = mount->read_only;
}
// Nothing to do if getting the mount itself.
if (corrected_path == mount->mount) {
return mount->host_path;

View file

@ -22,16 +22,19 @@ public:
struct MntPair {
std::filesystem::path host_path;
std::string mount; // e.g /app0/
bool read_only;
};
explicit MntPoints() = default;
~MntPoints() = default;
void Mount(const std::filesystem::path& host_folder, const std::string& guest_folder);
void Mount(const std::filesystem::path& host_folder, const std::string& guest_folder,
bool read_only = false);
void Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder);
void UnmountAll();
std::filesystem::path GetHostPath(std::string_view guest_directory);
std::filesystem::path GetHostPath(std::string_view guest_directory,
bool* is_read_only = nullptr);
const MntPair* GetMount(const std::string& guest_path) {
std::scoped_lock lock{m_mutex};

View file

@ -179,11 +179,16 @@ int PS4_SYSV_ABI sceKernelUnlink(const char* path) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto host_path = mnt->GetHostPath(path);
bool ro = false;
const auto host_path = mnt->GetHostPath(path, &ro);
if (host_path.empty()) {
return SCE_KERNEL_ERROR_EACCES;
}
if (ro) {
return SCE_KERNEL_ERROR_EROFS;
}
if (std::filesystem::is_directory(host_path)) {
return SCE_KERNEL_ERROR_EPERM;
}
@ -270,11 +275,18 @@ int PS4_SYSV_ABI sceKernelMkdir(const char* path, u16 mode) {
return SCE_KERNEL_ERROR_EINVAL;
}
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto dir_name = mnt->GetHostPath(path);
bool ro = false;
const auto dir_name = mnt->GetHostPath(path, &ro);
if (std::filesystem::exists(dir_name)) {
return SCE_KERNEL_ERROR_EEXIST;
}
if (ro) {
return SCE_KERNEL_ERROR_EROFS;
}
// CUSA02456: path = /aotl after sceSaveDataMount(mode = 1)
if (dir_name.empty() || !std::filesystem::create_directory(dir_name)) {
return SCE_KERNEL_ERROR_EIO;
@ -299,7 +311,8 @@ int PS4_SYSV_ABI posix_mkdir(const char* path, u16 mode) {
int PS4_SYSV_ABI sceKernelStat(const char* path, OrbisKernelStat* sb) {
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto path_name = mnt->GetHostPath(path);
bool ro = false;
const auto path_name = mnt->GetHostPath(path, &ro);
std::memset(sb, 0, sizeof(OrbisKernelStat));
const bool is_dir = std::filesystem::is_directory(path_name);
const bool is_file = std::filesystem::is_regular_file(path_name);
@ -319,6 +332,10 @@ int PS4_SYSV_ABI sceKernelStat(const char* path, OrbisKernelStat* sb) {
sb->st_blocks = (sb->st_size + 511) / 512;
// TODO incomplete
}
if (ro) {
sb->st_mode &= ~0000555u;
}
return ORBIS_OK;
}
@ -500,11 +517,18 @@ s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) {
s32 PS4_SYSV_ABI sceKernelRename(const char* from, const char* to) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto src_path = mnt->GetHostPath(from);
bool ro = false;
const auto src_path = mnt->GetHostPath(from, &ro);
if (!std::filesystem::exists(src_path)) {
return ORBIS_KERNEL_ERROR_ENOENT;
}
const auto dst_path = mnt->GetHostPath(to);
if (ro) {
return SCE_KERNEL_ERROR_EROFS;
}
const auto dst_path = mnt->GetHostPath(to, &ro);
if (ro) {
return SCE_KERNEL_ERROR_EROFS;
}
const bool src_is_dir = std::filesystem::is_directory(src_path);
const bool dst_is_dir = std::filesystem::is_directory(dst_path);
if (src_is_dir && !dst_is_dir) {