sys_fs: Fix O_CREATE and O_TRUNC for BDVD

This commit is contained in:
Elad 2026-04-21 12:53:25 +03:00
parent 3cca094d2d
commit 1ca8ab393a
3 changed files with 29 additions and 27 deletions

View File

@ -861,7 +861,7 @@ error_code sys_fs_test(ppu_thread&, u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 a
return CELL_OK;
}
lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s32 flags, s32 /*mode*/, lv2_file_type type, const lv2_fs_mount_info& mp)
lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s32 flags, bool has_write_access, lv2_file_type type, const lv2_fs_mount_info& mp)
{
// TODO: other checks for path
@ -888,7 +888,7 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
}
}
if (flags & CELL_FS_O_CREAT)
if (flags & CELL_FS_O_CREAT && !mp.read_only)
{
open_mode += fs::create;
@ -898,7 +898,7 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
}
}
if (flags & CELL_FS_O_TRUNC)
if (flags & CELL_FS_O_TRUNC && !mp.read_only)
{
open_mode += fs::trunc;
}
@ -906,6 +906,7 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
if (flags & CELL_FS_O_MSELF)
{
open_mode = fs::read;
// mself can be mself or mself | rdonly
if (flags & ~(CELL_FS_O_MSELF | CELL_FS_O_RDONLY))
{
@ -918,7 +919,7 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
sys_fs.warning("lv2_file::open() called with CELL_FS_O_UNK flag enabled. FLAGS: %#o", flags);
}
if (mp.read_only)
if (mp.read_only || !has_write_access)
{
// Deactivate mutating flags on read-only FS
open_mode = fs::read;
@ -970,12 +971,12 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
if (!file)
{
if (mp.read_only)
if (mp.read_only || !has_write_access)
{
// Failed to create file on read-only FS (file doesn't exist)
if (flags & CELL_FS_O_ACCMODE && flags & CELL_FS_O_CREAT)
if (flags & CELL_FS_O_CREAT)
{
return {CELL_EPERM};
return {mp.read_only ? CELL_EPERM : CELL_EACCES};
}
}
@ -988,6 +989,7 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
{
case fs::error::notdir: return {CELL_ENOTDIR};
case fs::error::noent: return {CELL_ENOENT};
case fs::error::isdir: return {CELL_EISDIR};
default:
{
if (has_non_directory_components(local_path))
@ -1000,6 +1002,11 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
}
}
if (flags & CELL_FS_O_TRUNC && (mp.read_only || !has_write_access))
{
return {mp.read_only ? CELL_EPERM : CELL_EACCES};
}
if (flags & CELL_FS_O_MSELF && !verify_mself(file))
{
return {CELL_ENOTMSELF};
@ -1113,11 +1120,6 @@ lv2_file::open_result_t lv2_file::open(std::string_view vpath, s32 flags, s32 mo
return {CELL_ENOTMOUNTED, path};
}
if (flags & CELL_FS_O_CREAT && !has_fs_write_rights(vpath) && !fs::is_dir(local_path))
{
return {CELL_EACCES};
}
lv2_file_type type = lv2_file_type::regular;
if (size == 8)
@ -1132,7 +1134,7 @@ lv2_file::open_result_t lv2_file::open(std::string_view vpath, s32 flags, s32 mo
}
}
auto [error, file] = open_raw(local_path, flags, mode, type, mp);
auto [error, file] = open_raw(local_path, flags, has_fs_write_rights(vpath), type, mp);
return {.error = error, .ppath = std::move(path), .real_path = std::move(local_path), .file = std::move(file), .type = type};
}
@ -1823,13 +1825,13 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
return {CELL_EROFS, path};
}
std::lock_guard lock(mp->mutex);
if (!fs::exists(local_path) && !has_fs_write_rights(path.get_ptr()))
{
return {CELL_EACCES, path};
}
std::lock_guard lock(mp->mutex);
if (!fs::create_dir(local_path))
{
switch (auto error = fs::g_tls_error)
@ -1953,26 +1955,26 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
if (mp == &g_mp_sys_dev_root)
{
return {CELL_EPERM, path};
return {CELL_EPERM, vpath};
}
if (local_path.empty())
{
return {CELL_ENOTMOUNTED, path};
return {CELL_ENOTMOUNTED, vpath};
}
if (mp.read_only)
{
return {CELL_EROFS, path};
}
if (fs::is_dir(local_path) && !has_fs_write_rights(path.get_ptr()))
{
return {CELL_EACCES};
return {CELL_EROFS, vpath};
}
std::lock_guard lock(mp->mutex);
if (fs::is_dir(local_path) && !has_fs_write_rights(vpath))
{
return {CELL_EACCES, vpath};
}
if (!fs::remove_dir(local_path))
{
switch (auto error = fs::g_tls_error)
@ -1984,7 +1986,7 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
return { CELL_ENOTDIR, vpath };
}
fmt::throw_exception("unknown error %s", error);
@ -1992,7 +1994,7 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
}
}
sys_fs.notice("sys_fs_rmdir(): directory %s removed", path);
sys_fs.notice("sys_fs_rmdir(): directory %s removed", vpath);
return CELL_OK;
}

View File

@ -341,7 +341,7 @@ struct lv2_file final : lv2_fs_object
};
// Open a file with wrapped logic of sys_fs_open
static open_raw_result_t open_raw(const std::string& path, s32 flags, s32 mode, lv2_file_type type = lv2_file_type::regular, const lv2_fs_mount_info& mp = g_mi_sys_not_found);
static open_raw_result_t open_raw(const std::string& path, s32 flags, bool has_write_access, lv2_file_type type = lv2_file_type::regular, const lv2_fs_mount_info& mp = g_mi_sys_not_found);
static open_result_t open(std::string_view vpath, s32 flags, s32 mode, const void* arg = {}, u64 size = 0);
// File reading with intermediate buffer

View File

@ -1028,7 +1028,7 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2
}
// Reopen with ignored TRUNC, APPEND, CREATE and EXCL flags
auto res0 = lv2_file::open_raw(file.real_path, file.flags & CELL_FS_O_ACCMODE, file.mode, file.type, file.mp);
auto res0 = lv2_file::open_raw(file.real_path, file.flags & CELL_FS_O_ACCMODE, true, file.type, file.mp);
file.file = std::move(res0.file);
ensure(file.file.operator bool());
file.file.seek(file.restore_data.seek_pos);