sys_fs: Implement ENOTDIR

This commit is contained in:
Elad 2026-03-30 23:04:44 +03:00 committed by Ani
parent 122ccca50e
commit bd95c728f0
4 changed files with 150 additions and 15 deletions

View File

@ -166,6 +166,7 @@ static fs::error to_error(int e)
case ENOTEMPTY: return fs::error::notempty;
case EROFS: return fs::error::readonly;
case EISDIR: return fs::error::isdir;
case ENOTDIR: return fs::error::notdir;
case ENOSPC: return fs::error::nospace;
case EXDEV: return fs::error::xdev;
default: return fs::error::unknown;
@ -2833,6 +2834,7 @@ void fmt_class_string<fs::error>::format(std::string& out, u64 arg)
case fs::error::notempty: return "Not empty";
case fs::error::readonly: return "Read only";
case fs::error::isdir: return "Is a directory";
case fs::error::notdir: return "Not a directory";
case fs::error::toolong: return "Path too long";
case fs::error::nospace: return "Not enough space on the device";
case fs::error::xdev: return "Device mismatch";

View File

@ -683,6 +683,7 @@ namespace fs
notempty,
readonly,
isdir,
notdir,
toolong,
nospace,
xdev,

View File

@ -140,6 +140,32 @@ bool verify_mself(const fs::file& mself_file)
return true;
}
// TODO: May not be thread-safe (or even, process-safe)
bool has_non_directory_components(std::string_view path)
{
std::string path0{path};
while (true)
{
const std::string sub_path = fs::get_parent_dir(path0);
if (sub_path.size() >= path0.size())
{
break;
}
fs::stat_t stat{};
if (fs::get_stat(sub_path, stat))
{
return !stat.is_directory;
}
path0 = std::move(sub_path);
}
return false;
}
lv2_fs_mount_info_map::lv2_fs_mount_info_map()
{
for (auto mp = &g_mp_sys_dev_root; mp; mp = mp->next) // Scan and keep track of pre-mounted devices
@ -899,8 +925,17 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir: return {CELL_ENOTDIR};
case fs::error::noent: return {CELL_ENOENT};
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_path))
{
return {CELL_ENOTDIR};
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -1372,6 +1407,11 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
}
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
@ -1555,6 +1595,10 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir:
{
return { CELL_ENOTDIR, path};
}
case fs::error::noent:
{
// Try to analyse split file (TODO)
@ -1594,6 +1638,11 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
}
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
@ -1720,6 +1769,10 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir:
{
return { CELL_ENOTDIR, path};
}
case fs::error::noent:
{
return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path};
@ -1728,7 +1781,15 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
{
return {sys_fs.warning, CELL_EEXIST, path};
}
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -1789,9 +1850,18 @@ error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir: return {CELL_ENOTDIR, from};
case fs::error::noent: return {CELL_ENOENT, from};
case fs::error::exist: return {CELL_EEXIST, to};
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_from))
{
return {CELL_ENOTDIR, from};
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -1842,9 +1912,18 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir: return {CELL_ENOTDIR, path};
case fs::error::noent: return {CELL_ENOENT, path};
case fs::error::notempty: return {CELL_ENOTEMPTY, path};
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -1896,11 +1975,23 @@ error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr<char> path)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir:
{
return { CELL_ENOTDIR, path };
}
case fs::error::noent:
{
return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path};
}
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -2737,7 +2828,15 @@ error_code sys_fs_get_block_size(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u
{
case fs::error::exist: return {CELL_EISDIR, path};
case fs::error::noent: return {CELL_ENOENT, path};
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -2789,11 +2888,23 @@ error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir:
{
return { CELL_ENOTDIR, path};
}
case fs::error::noent:
{
return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path};
}
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -2840,7 +2951,10 @@ error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size)
switch (auto error = fs::g_tls_error)
{
case fs::error::ok:
default: fmt::throw_exception("unknown error %s", error);
default:
{
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -2887,6 +3001,10 @@ error_code sys_fs_chmod(ppu_thread&, vm::cptr<char> path, s32 mode)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir:
{
return { CELL_ENOTDIR, path};
}
case fs::error::noent:
{
// Try to locate split files
@ -2900,8 +3018,12 @@ error_code sys_fs_chmod(ppu_thread&, vm::cptr<char> path, s32 mode)
}
default:
{
sys_fs.error("sys_fs_chmod(): unknown error %s", error);
return {CELL_EIO, path};
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
}
@ -3033,11 +3155,23 @@ error_code sys_fs_utime(ppu_thread& ppu, vm::cptr<char> path, vm::cptr<CellFsUti
{
switch (auto error = fs::g_tls_error)
{
case fs::error::notdir:
{
return { CELL_ENOTDIR, path};
}
case fs::error::noent:
{
return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path};
}
default: fmt::throw_exception("unknown error %s", error);
default:
{
if (has_non_directory_components(local_path))
{
return { CELL_ENOTDIR, path };
}
fmt::throw_exception("unknown error %s", error);
}
}
}

View File

@ -585,10 +585,8 @@ std::unique_ptr<fs::dir_base> iso_device::open_dir(const std::string& path)
if (!node->metadata.is_directory)
{
// fs::dir::open -> ::readdir should return ENOTDIR when path is
// pointing to a file instead of a folder, which translates to error::unknown.
// doing the same here.
fs::g_tls_error = fs::error::unknown;
// fs::dir::open -> ::readdir should return ENOTDIR when path is pointing to a file instead of a folder.
fs::g_tls_error = fs::error::notdir;
return nullptr;
}