mirror of https://github.com/RPCS3/rpcs3.git
Rewrite sys_fs_opendir
Rewrite lv2_dir object Support split files and mount points
This commit is contained in:
parent
c5676e5649
commit
b94e98aed5
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue