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
+27 -25
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; 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 // 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; 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; 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) if (flags & CELL_FS_O_MSELF)
{ {
open_mode = fs::read; open_mode = fs::read;
// mself can be mself or mself | rdonly // mself can be mself or mself | rdonly
if (flags & ~(CELL_FS_O_MSELF | CELL_FS_O_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); 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 // Deactivate mutating flags on read-only FS
open_mode = fs::read; 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 (!file)
{ {
if (mp.read_only) if (mp.read_only || !has_write_access)
{ {
// Failed to create file on read-only FS (file doesn't exist) // 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::notdir: return {CELL_ENOTDIR};
case fs::error::noent: return {CELL_ENOENT}; case fs::error::noent: return {CELL_ENOENT};
case fs::error::isdir: return {CELL_EISDIR};
default: default:
{ {
if (has_non_directory_components(local_path)) 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)) if (flags & CELL_FS_O_MSELF && !verify_mself(file))
{ {
return {CELL_ENOTMSELF}; 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}; 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; lv2_file_type type = lv2_file_type::regular;
if (size == 8) 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}; 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}; return {CELL_EROFS, path};
} }
std::lock_guard lock(mp->mutex);
if (!fs::exists(local_path) && !has_fs_write_rights(path.get_ptr())) if (!fs::exists(local_path) && !has_fs_write_rights(path.get_ptr()))
{ {
return {CELL_EACCES, path}; return {CELL_EACCES, path};
} }
std::lock_guard lock(mp->mutex);
if (!fs::create_dir(local_path)) if (!fs::create_dir(local_path))
{ {
switch (auto error = fs::g_tls_error) 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) if (mp == &g_mp_sys_dev_root)
{ {
return {CELL_EPERM, path}; return {CELL_EPERM, vpath};
} }
if (local_path.empty()) if (local_path.empty())
{ {
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, vpath};
} }
if (mp.read_only) if (mp.read_only)
{ {
return {CELL_EROFS, path}; return {CELL_EROFS, vpath};
}
if (fs::is_dir(local_path) && !has_fs_write_rights(path.get_ptr()))
{
return {CELL_EACCES};
} }
std::lock_guard lock(mp->mutex); 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)) if (!fs::remove_dir(local_path))
{ {
switch (auto error = fs::g_tls_error) 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)) if (has_non_directory_components(local_path))
{ {
return { CELL_ENOTDIR, path }; return { CELL_ENOTDIR, vpath };
} }
fmt::throw_exception("unknown error %s", error); 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; return CELL_OK;
} }
+1 -1
View File
@@ -341,7 +341,7 @@ struct lv2_file final : lv2_fs_object
}; };
// Open a file with wrapped logic of sys_fs_open // 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); static open_result_t open(std::string_view vpath, s32 flags, s32 mode, const void* arg = {}, u64 size = 0);
// File reading with intermediate buffer // File reading with intermediate buffer
+1 -1
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 // 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); file.file = std::move(res0.file);
ensure(file.file.operator bool()); ensure(file.file.operator bool());
file.file.seek(file.restore_data.seek_pos); file.file.seek(file.restore_data.seek_pos);