sys_fs: implement CELL_EROFS error

Implement lv2_mp_flag::read_only.
Currently only /dev_bdvd is affected.
This commit is contained in:
Nekotekina 2020-01-05 00:55:15 +03:00
parent d5f0957558
commit bed2d558a6
1 changed files with 124 additions and 6 deletions

View File

@ -221,6 +221,8 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
const std::string_view vpath = path.get_ptr(); const std::string_view vpath = path.get_ptr();
const std::string local_path = vfs::get(vpath, nullptr, &processed_path); const std::string local_path = vfs::get(vpath, nullptr, &processed_path);
const auto mp = lv2_fs_object::get_mp(vpath);
if (vpath.find_first_not_of('/') == -1) if (vpath.find_first_not_of('/') == -1)
{ {
return {CELL_EISDIR, path}; return {CELL_EISDIR, path};
@ -282,6 +284,12 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
sys_fs.warning("sys_fs_open called with CELL_FS_O_UNK flag enabled. FLAGS: %#o", flags); sys_fs.warning("sys_fs_open called with CELL_FS_O_UNK flag enabled. FLAGS: %#o", flags);
} }
if (mp->flags & lv2_mp_flag::read_only)
{
// Deactivate mutating flags on read-only FS
open_mode = fs::read;
}
// Tests have shown that invalid combinations get resolved internally (without exceptions), but that would complicate code with minimal accuracy gains. // Tests have shown that invalid combinations get resolved internally (without exceptions), but that would complicate code with minimal accuracy gains.
// For example, no games are known to try and call TRUNCATE | APPEND | RW, or APPEND | READ, which currently would cause an exception. // For example, no games are known to try and call TRUNCATE | APPEND | RW, or APPEND | READ, which currently would cause an exception.
if (flags & ~(CELL_FS_O_UNK | CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_APPEND | CELL_FS_O_EXCL | CELL_FS_O_MSELF)) if (flags & ~(CELL_FS_O_UNK | CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_APPEND | CELL_FS_O_EXCL | CELL_FS_O_MSELF))
@ -299,7 +307,11 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
fmt::throw_exception("sys_fs_open(%s): Invalid or unimplemented flags: %#o" HERE, path, flags); fmt::throw_exception("sys_fs_open(%s): Invalid or unimplemented flags: %#o" HERE, path, flags);
} }
fs::file file(local_path, open_mode); fs::file file;
{
std::lock_guard lock(mp->mutex);
file.open(local_path, open_mode);
}
if (!file && open_mode == fs::read && fs::g_tls_error == fs::error::noent) if (!file && open_mode == fs::read && fs::g_tls_error == fs::error::noent)
{ {
@ -326,6 +338,15 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
if (!file) if (!file)
{ {
if (mp->flags & lv2_mp_flag::read_only)
{
// Failed to create file on read-only FS (file doesn't exist)
if (flags & CELL_FS_O_CREAT)
{
return {CELL_EROFS, path};
}
}
if (open_mode & fs::excl && fs::g_tls_error == fs::error::exist) if (open_mode & fs::excl && fs::g_tls_error == fs::error::exist)
{ {
return not_an_error(CELL_EEXIST); return not_an_error(CELL_EEXIST);
@ -340,6 +361,21 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
return {CELL_EIO, path}; return {CELL_EIO, path};
} }
if (mp->flags & lv2_mp_flag::read_only)
{
// Failed to create file on read-only FS (file exists)
if (flags & CELL_FS_O_CREAT && flags & CELL_FS_O_EXCL)
{
return {CELL_EEXIST, path};
}
// Failed to truncate file on read-only FS
if (flags & CELL_FS_O_TRUNC)
{
return {CELL_EROFS, path};
}
}
if ((flags & CELL_FS_O_MSELF) && (!verify_mself(*fd, file))) if ((flags & CELL_FS_O_MSELF) && (!verify_mself(*fd, file)))
{ {
return {CELL_ENOTMSELF, path}; return {CELL_ENOTMSELF, path};
@ -441,6 +477,11 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
return CELL_EBADF; return CELL_EBADF;
} }
if (file->mp->flags & lv2_mp_flag::read_only)
{
return CELL_EROFS;
}
std::lock_guard lock(file->mp->mutex); std::lock_guard lock(file->mp->mutex);
if (file->lock) if (file->lock)
@ -506,6 +547,8 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
processed_path += "/"; processed_path += "/";
const auto mp = lv2_fs_object::get_mp(vpath);
if (local_path.empty() && ext.empty()) if (local_path.empty() && ext.empty())
{ {
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, path};
@ -518,7 +561,11 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
return {CELL_ENOTDIR, path}; return {CELL_ENOTDIR, path};
} }
fs::dir dir(local_path); fs::dir dir;
{
std::lock_guard lock(mp->mutex);
dir.open(local_path);
}
if (!dir) if (!dir)
{ {
@ -657,9 +704,9 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
const std::string_view vpath = path.get_ptr(); const std::string_view vpath = path.get_ptr();
const std::string local_path = vfs::get(vpath); const std::string local_path = vfs::get(vpath);
const auto first_name_ch = vpath.find_first_not_of('/'); const auto mp = lv2_fs_object::get_mp(vpath);
if (first_name_ch == -1) if (vpath.find_first_not_of('/') == -1)
{ {
*sb = {CELL_FS_S_IFDIR | 0444}; *sb = {CELL_FS_S_IFDIR | 0444};
return CELL_OK; return CELL_OK;
@ -670,6 +717,8 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, path};
} }
std::lock_guard lock(mp->mutex);
fs::stat_t info{}; fs::stat_t info{};
if (!fs::stat(local_path, info)) if (!fs::stat(local_path, info))
@ -713,8 +762,6 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
} }
} }
const auto mp = lv2_fs_object::get_mp(vpath);
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
sb->uid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0; sb->uid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
sb->gid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0; sb->gid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
@ -793,6 +840,15 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, path};
} }
const auto mp = lv2_fs_object::get_mp(vpath);
if (mp->flags & lv2_mp_flag::read_only)
{
return {CELL_EROFS, 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)
@ -831,6 +887,20 @@ error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to
return CELL_ENOTMOUNTED; return CELL_ENOTMOUNTED;
} }
const auto mp = lv2_fs_object::get_mp(vfrom);
if (mp != lv2_fs_object::get_mp(vto))
{
return CELL_EXDEV;
}
if (mp->flags & lv2_mp_flag::read_only)
{
return CELL_EROFS;
}
std::lock_guard lock(mp->mutex);
if (!vfs::host::rename(local_from, local_to, false)) if (!vfs::host::rename(local_from, local_to, false))
{ {
switch (auto error = fs::g_tls_error) switch (auto error = fs::g_tls_error)
@ -872,6 +942,15 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, path};
} }
const auto mp = lv2_fs_object::get_mp(vpath);
if (mp->flags & lv2_mp_flag::read_only)
{
return {CELL_EROFS, path};
}
std::lock_guard lock(mp->mutex);
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)
@ -920,6 +999,15 @@ error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr<char> path)
return {CELL_EISDIR, path}; return {CELL_EISDIR, path};
} }
const auto mp = lv2_fs_object::get_mp(vpath);
if (mp->flags & lv2_mp_flag::read_only)
{
return {CELL_EROFS, path};
}
std::lock_guard lock(mp->mutex);
// Size of "/dev_hdd0"-alike substring // Size of "/dev_hdd0"-alike substring
const std::size_t dev_size = vpath.find_first_of('/', dev_start); const std::size_t dev_size = vpath.find_first_of('/', dev_start);
@ -995,6 +1083,11 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
return CELL_EBADF; return CELL_EBADF;
} }
if (op == 0x8000000b && file->mp->flags & lv2_mp_flag::read_only)
{
return CELL_EROFS;
}
std::lock_guard lock(file->mp->mutex); std::lock_guard lock(file->mp->mutex);
if (op == 0x8000000b && file->lock) if (op == 0x8000000b && file->lock)
@ -1388,6 +1481,7 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
return CELL_EBADF; return CELL_EBADF;
} }
std::lock_guard lock(file->mp->mutex);
file->file.sync(); file->file.sync();
return CELL_OK; return CELL_OK;
} }
@ -1405,6 +1499,7 @@ error_code sys_fs_fsync(ppu_thread& ppu, u32 fd)
return CELL_EBADF; return CELL_EBADF;
} }
std::lock_guard lock(file->mp->mutex);
file->file.sync(); file->file.sync();
return CELL_OK; return CELL_OK;
} }
@ -1466,6 +1561,15 @@ error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size)
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, path};
} }
const auto mp = lv2_fs_object::get_mp(vpath);
if (mp->flags & lv2_mp_flag::read_only)
{
return {CELL_EROFS, path};
}
std::lock_guard lock(mp->mutex);
if (!fs::truncate_file(local_path, size)) if (!fs::truncate_file(local_path, size))
{ {
switch (auto error = fs::g_tls_error) switch (auto error = fs::g_tls_error)
@ -1493,6 +1597,11 @@ error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size)
return CELL_EBADF; return CELL_EBADF;
} }
if (file->mp->flags & lv2_mp_flag::read_only)
{
return CELL_EROFS;
}
std::lock_guard lock(file->mp->mutex); std::lock_guard lock(file->mp->mutex);
if (file->lock == 2) if (file->lock == 2)
@ -1618,6 +1727,15 @@ error_code sys_fs_utime(ppu_thread& ppu, vm::cptr<char> path, vm::cptr<CellFsUti
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, path};
} }
const auto mp = lv2_fs_object::get_mp(vpath);
if (mp->flags & lv2_mp_flag::read_only)
{
return {CELL_EROFS, path};
}
std::lock_guard lock(mp->mutex);
if (!fs::utime(local_path, timep->actime, timep->modtime)) if (!fs::utime(local_path, timep->actime, timep->modtime))
{ {
switch (auto error = fs::g_tls_error) switch (auto error = fs::g_tls_error)