Implement lv2_file::open()

Return accurate error codes in prx_load_module, sys_spu_image_open and overlay_load_module.
This commit is contained in:
Eladash 2020-03-06 14:47:24 +02:00 committed by Ivan
parent acd50eefaf
commit 1669e95870
5 changed files with 96 additions and 33 deletions

View File

@ -27,7 +27,7 @@ lv2_fs_mount_point g_mp_sys_app_home{512, 512, lv2_mp_flag::strict_get_block_siz
lv2_fs_mount_point g_mp_sys_host_root{512, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_flash{512, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid};
bool verify_mself(u32 fd, fs::file const& mself_file)
bool verify_mself(const fs::file& mself_file)
{
FsMselfHeader mself_header;
if (!mself_file.read<FsMselfHeader>(mself_header))
@ -240,23 +240,17 @@ error_code sys_fs_test(ppu_thread& ppu, u32 arg1, u32 arg2, vm::ptr<u32> arg3, u
return CELL_OK;
}
error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
lv2_file::open_result_t lv2_file::open(std::string_view vpath, s32 flags, s32 mode, const void* arg, u64 size)
{
lv2_obj::sleep(ppu);
if (vpath.empty())
{
return {CELL_ENOENT};
}
sys_fs.warning("sys_fs_open(path=%s, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size);
std::string path;
const std::string local_path = vfs::get(vpath, nullptr, &path);
if (!path)
return CELL_EFAULT;
if (!path[0])
return CELL_ENOENT;
std::string processed_path;
const std::string_view vpath = path.get_ptr();
const std::string local_path = vfs::get(vpath, nullptr, &processed_path);
const auto mp = lv2_fs_object::get_mp(vpath);
const auto mp = lv2_fs_object::get_mp(path);
if (vpath.find_first_not_of('/') == umax)
{
@ -319,7 +313,7 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
if (flags & CELL_FS_O_UNK)
{
sys_fs.warning("sys_fs_open called with CELL_FS_O_UNK flag enabled. FLAGS: %#o", flags);
sys_fs.warning("lv2_file::open() called with CELL_FS_O_UNK flag enabled. FLAGS: %#o", flags);
}
if (mp->flags & lv2_mp_flag::read_only)
@ -342,7 +336,7 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
if (!open_mode)
{
fmt::throw_exception("sys_fs_open(%s): Invalid or unimplemented flags: %#o" HERE, path, flags);
fmt::throw_exception("lv2_file::open(%s): Invalid or unimplemented flags: %#o" HERE, path, flags);
}
fs::file file;
@ -387,13 +381,13 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
if (open_mode & fs::excl && fs::g_tls_error == fs::error::exist)
{
return not_an_error(CELL_EEXIST);
return {CELL_EEXIST};
}
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return {CELL_ENOENT, path};
default: sys_fs.error("sys_fs_open(): unknown error %s", error);
default: sys_fs.error("lv2_file::open(): unknown error %s", error);
}
return {CELL_EIO, path};
@ -414,17 +408,17 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
}
}
if ((flags & CELL_FS_O_MSELF) && (!verify_mself(*fd, file)))
if (flags & CELL_FS_O_MSELF && !verify_mself(file))
{
return {CELL_ENOTMSELF, path};
}
const auto casted_arg = vm::static_ptr_cast<const u64>(arg);
if (size == 8)
{
// check for sdata
if (*casted_arg == 0x18000000010ull)
switch (*static_cast<const be_t<u64>*>(arg))
{
case 0x18000000010:
{
// check if the file has the NPD header, or else assume its not encrypted
u32 magic;
@ -440,9 +434,11 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
file.reset(std::move(sdata_file));
}
break;
}
// edata
else if (*casted_arg == 0x2u)
case 0x2:
{
// check if the file has the NPD header, or else assume its not encrypted
u32 magic;
@ -459,10 +455,38 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
file.reset(std::move(sdata_file));
}
break;
}
default: break;
}
}
if (const u32 id = idm::make<lv2_fs_object, lv2_file>(processed_path, std::move(file), mode, flags))
return {.error = {}, .ppath = path, .file = std::move(file)};
}
error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
{
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_open(path=%s, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size);
if (!path)
return CELL_EFAULT;
auto [error, ppath, file] = lv2_file::open(path.get_ptr(), flags, mode, arg.get_ptr(), size);
if (error)
{
if (error == CELL_EEXIST)
{
return not_an_error(CELL_EEXIST);
}
return {error, path};
}
if (const u32 id = idm::make<lv2_fs_object, lv2_file>(ppath, std::move(file), mode, flags))
{
*fd = id;
return CELL_OK;

View File

@ -4,6 +4,8 @@
#include "Emu/Cell/ErrorCodes.h"
#include "Utilities/File.h"
#include <string>
// Open Flags
enum : s32
{
@ -192,6 +194,16 @@ struct lv2_file final : lv2_fs_object
{
}
struct open_result_t
{
CellError error;
std::string ppath;
fs::file file;
};
// Open a file with wrapped logic of sys_fs_open
static open_result_t open(std::string_view path, s32 flags, s32 mode, const void* arg = {}, u64 size = 0);
// File reading with intermediate buffer
static u64 op_read(const fs::file& file, vm::ptr<void> buf, u64 size);

View File

@ -19,11 +19,16 @@ LOG_CHANNEL(sys_overlay);
static error_code overlay_load_module(vm::ptr<u32> ovlmid, const std::string& vpath, u64 flags, vm::ptr<u32> entry, fs::file src = {})
{
const std::string path = vfs::get(vpath);
if (!src)
{
src.open(path);
auto [fs_error, ppath, lv2_file] = lv2_file::open(vpath, 0, 0);
if (fs_error)
{
return {fs_error, vpath};
}
src = std::move(lv2_file);
}
const ppu_exec_object obj = decrypt_self(std::move(src), g_fxo->get<loaded_npdrm_keys>()->devKlic.data());
@ -33,7 +38,7 @@ static error_code overlay_load_module(vm::ptr<u32> ovlmid, const std::string& vp
return {CELL_ENOEXEC, obj.operator elf_error()};
}
const auto ovlm = ppu_load_overlay(obj, path);
const auto ovlm = ppu_load_overlay(obj, vfs::get(vpath));
ppu_initialize(*ovlm);
@ -92,6 +97,12 @@ error_code sys_overlay_unload_module(u32 ovlmid)
{
sys_overlay.warning("sys_overlay_unload_module(ovlmid=0x%x)", ovlmid);
if (!g_ps3_process_info.ppc_seg)
{
// Process not permitted
return CELL_ENOSYS;
}
const auto _main = idm::withdraw<lv2_obj, lv2_overlay>(ovlmid);
if (!_main)

View File

@ -6,6 +6,7 @@
#include "Crypto/unself.h"
#include "Loader/ELF.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Crypto/unedat.h"
#include "Utilities/StrUtil.h"
@ -154,7 +155,14 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<s
if (!src)
{
src.open(path);
auto [fs_error, ppath, lv2_file] = lv2_file::open(vpath, 0, 0);
if (fs_error)
{
return {fs_error, vpath};
}
src = std::move(lv2_file);
}
const ppu_prx_object obj = decrypt_self(std::move(src), g_fxo->get<loaded_npdrm_keys>()->devKlic.data());

View File

@ -18,6 +18,7 @@
#include "sys_memory.h"
#include "sys_mmapper.h"
#include "sys_event.h"
#include "sys_fs.h"
LOG_CHANNEL(sys_spu);
@ -217,12 +218,19 @@ error_code sys_spu_image_open(ppu_thread& ppu, vm::ptr<sys_spu_image> img, vm::c
sys_spu.warning("sys_spu_image_open(img=*0x%x, path=%s)", img, path);
const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr())), g_fxo->get<loaded_npdrm_keys>()->devKlic.data());
auto [fs_error, ppath, file] = lv2_file::open(path.get_ptr(), 0, 0);
if (fs_error)
{
return {fs_error, path};
}
const fs::file elf_file = decrypt_self(std::move(file), g_fxo->get<loaded_npdrm_keys>()->devKlic.data());
if (!elf_file)
{
sys_spu.error("sys_spu_image_open() error: failed to open %s!", path);
return CELL_ENOENT;
sys_spu.error("sys_spu_image_open(): file %s is illegal for SPU image!", path);
return {CELL_ENOEXEC, path};
}
img->load(elf_file);