Rewrite sys_fs_opendir

Rewrite lv2_dir object
Support split files and mount points
This commit is contained in:
Nekotekina 2018-09-15 17:04:35 +03:00
parent c5676e5649
commit b94e98aed5
2 changed files with 97 additions and 35 deletions

View File

@ -468,16 +468,11 @@ error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
if (!path[0]) if (!path[0])
return CELL_ENOENT; return CELL_ENOENT;
std::vector<std::string> ext;
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, &ext);
if (vpath.find_first_not_of('/') == -1) if (local_path.empty() && ext.empty())
{
// TODO: open root
return {CELL_EPERM, path};
}
if (local_path.empty())
{ {
return {CELL_ENOTMOUNTED, path}; return {CELL_ENOTMOUNTED, path};
} }
@ -495,14 +490,73 @@ error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
{ {
switch (auto error = fs::g_tls_error) switch (auto error = fs::g_tls_error)
{ {
case fs::error::noent: return {CELL_ENOENT, path}; case fs::error::noent:
default: sys_fs.error("sys_fs_opendir(): unknown error %s", error); {
} if (ext.empty())
{
return {CELL_ENOENT, path};
}
return {CELL_EIO, path}; break;
}
default:
{
sys_fs.error("sys_fs_opendir(): unknown error %s", error);
return {CELL_EIO, path};
}
}
} }
if (const u32 id = idm::make<lv2_fs_object, lv2_dir>(path.get_ptr(), std::move(dir))) // Build directory as a vector of entries
std::vector<fs::dir_entry> data;
if (dir)
{
// Add real directories
while (dir.read(data.emplace_back()))
{
// Preprocess entries
data.back().name = vfs::unescape(data.back().name);
// Add additional entries for split file candidates (while ends with .66600)
while (data.back().name.size() >= 6 && data.back().name.compare(data.back().name.size() - 6, 6, ".66600", 6) == 0)
{
data.emplace_back(data.back()).name.resize(data.back().name.size() - 6);
}
}
data.resize(data.size() - 1);
}
else
{
data.emplace_back().name = ".";
data.back().is_directory = true;
data.emplace_back().name = "..";
data.back().is_directory = true;
}
// Add mount points (TODO)
for (auto&& ex : ext)
{
data.emplace_back().name = std::move(ex);
data.back().is_directory = true;
}
// Sort files, keeping . and ..
std::stable_sort(data.begin() + 2, data.end(), [](const fs::dir_entry& a, const fs::dir_entry& b)
{
return a.name < b.name;
});
// Remove duplicates
const auto last = std::unique(data.begin(), data.end(), [](const fs::dir_entry& a, const fs::dir_entry& b)
{
return a.name == b.name;
});
data.erase(last, data.end());
if (const u32 id = idm::make<lv2_fs_object, lv2_dir>(path.get_ptr(), std::move(data)))
{ {
*fd = id; *fd = id;
return CELL_OK; return CELL_OK;
@ -523,14 +577,11 @@ error_code sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
return CELL_EBADF; return CELL_EBADF;
} }
fs::dir_entry info; if (auto* info = directory->dir_read())
if (directory->dir.read(info))
{ {
const std::string vfs_name = vfs::unescape(info.name); dir->d_type = info->is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
dir->d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; dir->d_namlen = u8(std::min<size_t>(info->name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
dir->d_namlen = u8(std::min<size_t>(vfs_name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); strcpy_trunc(dir->d_name, info->name);
strcpy_trunc(dir->d_name, vfs_name);
*nread = sizeof(CellFsDirent); *nread = sizeof(CellFsDirent);
} }
else else
@ -1109,25 +1160,22 @@ error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr<void> _arg, u32 _size)
for (; arg->_size < arg->max; arg->_size++) for (; arg->_size < arg->max; arg->_size++)
{ {
fs::dir_entry info; if (auto* info = directory->dir_read())
if (directory->dir.read(info))
{ {
auto& entry = arg->ptr[arg->_size]; auto& entry = arg->ptr[arg->_size];
entry.attribute.mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; entry.attribute.mode = info->is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
entry.attribute.uid = 0; entry.attribute.uid = 0;
entry.attribute.gid = 0; entry.attribute.gid = 0;
entry.attribute.atime = info.atime; entry.attribute.atime = info->atime;
entry.attribute.mtime = info.mtime; entry.attribute.mtime = info->mtime;
entry.attribute.ctime = info.ctime; entry.attribute.ctime = info->ctime;
entry.attribute.size = info.size; entry.attribute.size = info->size;
entry.attribute.blksize = 4096; // ??? entry.attribute.blksize = 4096; // ???
const std::string vfs_name = vfs::unescape(info.name); entry.entry_name.d_type = info->is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
entry.entry_name.d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; entry.entry_name.d_namlen = u8(std::min<size_t>(info->name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
entry.entry_name.d_namlen = u8(std::min<size_t>(vfs_name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); strcpy_trunc(entry.entry_name.d_name, info->name);
strcpy_trunc(entry.entry_name.d_name, vfs_name);
} }
else else
{ {

View File

@ -201,13 +201,27 @@ struct lv2_file final : lv2_fs_object
struct lv2_dir final : lv2_fs_object struct lv2_dir final : lv2_fs_object
{ {
const fs::dir dir; const std::vector<fs::dir_entry> entries;
lv2_dir(const char* filename, fs::dir&& dir) // Current reading position
atomic_t<u64> pos{0};
lv2_dir(const char* filename, std::vector<fs::dir_entry>&& entries)
: lv2_fs_object(lv2_fs_object::get_mp(filename), filename) : lv2_fs_object(lv2_fs_object::get_mp(filename), filename)
, dir(std::move(dir)) , entries(std::move(entries))
{ {
} }
// Read next
const fs::dir_entry* dir_read()
{
if (const u64 cur = pos++; cur < entries.size())
{
return &entries[cur];
}
return nullptr;
}
}; };
// sys_fs_fcntl arg base class (left empty for PODness) // sys_fs_fcntl arg base class (left empty for PODness)