Windows shenanigans

Modified FS init flow
Added mk/rmdir, fixed close()
Added (p)read/write
Fixed path being treated as relative on windows
Fixed incorrect resolution of mountpoint roots (requires validation)
This commit is contained in:
marecl 2025-11-05 14:51:02 +01:00
parent 1c8f24945a
commit 6b338d860a
8 changed files with 140 additions and 74 deletions

View File

@ -91,14 +91,14 @@ public:
s32 Truncate(const fs::path& path, u64 size) override;
s32 FTruncate(const s32 fd, u64 size) override;
// s64 Write(const s32 fd, const void* buf, u64 count) override;
// s64 Read(const s32 fd, void* buf, u64 count) override;
s64 Write(const s32 fd, const void* buf, u64 count) override;
s64 Read(const s32 fd, void* buf, u64 count) override;
// s64 PWrite(const s32 fd, const void* buf, u64 count, u64 offset) override;
// s64 PRead(const s32 fd, void* buf, u64 count, u64 offset) override;
s64 PWrite(const s32 fd, const void* buf, u64 count, u64 offset) override;
s64 PRead(const s32 fd, void* buf, u64 count, u64 offset) override;
// s32 MKDir(const fs::path& path, u16 mode = 0755) override;
// s32 RMDir(const fs::path& path) override;
s32 MKDir(const fs::path& path, u16 mode = 0755) override;
s32 RMDir(const fs::path& path) override;
// s32 Stat(const fs::path& path, Libraries::Kernel::OrbisKernelStat* statbuf) override;
// s32 FStat(const s32 fd, Libraries::Kernel::OrbisKernelStat* statbuf) override;

View File

@ -25,6 +25,8 @@ s32 HostIO_Win32::Creat(const fs::path& path, u16 mode) {
s32 HostIO_Win32::Close(const s32 fd) {
errno = 0;
if (fd < 0)
return -EBADF;
s32 status = _close(fd);
return 0 == status ? 0 : -errno;
}
@ -84,4 +86,60 @@ int HostIO_Win32::FTruncate(const s32 fd, u64 size) {
return status >= 0 ? status : -errno;
}
s64 HostIO_Win32::Write(const s32 fd, const void* buf, u64 count) {
errno = 0;
s32 status = _write(fd, buf, count);
return status >= 0 ? status : -errno;
}
s64 HostIO_Win32::Read(const s32 fd, void* buf, u64 count) {
errno = 0;
s32 status = _read(fd, buf, count);
return status >= 0 ? status : -errno;
}
s64 HostIO_Win32::PWrite(const s32 fd, const void* buf, u64 count, u64 offset) {
errno = 0;
s64 bak = LSeek(fd, 0, SeekOrigin::CURRENT);
if (bak < 0)
return -errno;
LSeek(fd, offset, SeekOrigin::ORIGIN);
s32 status = _write(fd, buf, count);
LSeek(fd, bak, SeekOrigin::ORIGIN);
return status >= 0 ? status : -errno;
}
s64 HostIO_Win32::PRead(const s32 fd, void* buf, u64 count, u64 offset) {
errno = 0;
s64 bak = LSeek(fd, 0, SeekOrigin::CURRENT);
if (bak < 0)
return -errno;
LSeek(fd, offset, SeekOrigin::ORIGIN);
s32 status = _read(fd, buf, count);
LSeek(fd, bak, SeekOrigin::ORIGIN);
return status >= 0 ? status : -errno;
}
s32 HostIO_Win32::MKDir(const fs::path& path, u16 mode) {
errno = 0;
s32 status = _wmkdir(path.c_str());
return status >= 0 ? status : -errno;
}
s32 HostIO_Win32::RMDir(const fs::path& path) {
errno = 0;
s32 status = _wrmdir(path.c_str());
return status >= 0 ? status : -errno;
}
// s32 HostIO_Win32::Stat(const fs::path& path, Libraries::Kernel::OrbisKernelStat* statbuf) {}
// s32 HostIO_Win32::FStat(const s32 fd, Libraries::Kernel::OrbisKernelStat* statbuf) {}
// s32 HostIO_Win32::Chmod(const fs::path& path, u16 mode) {}
// s32 HostIO_Win32::FChmod(const s32 fd, u16 mode) {}
} // namespace HostIODriver

View File

@ -228,10 +228,10 @@ int QFS::ForceInsert(const fs::path& path, const std::string& name, inode_ptr no
// DO NOT, AND I SWEAR D O N O T touch this function
// Debugging it is a royal PITA
int QFS::Resolve(const fs::path& path, Resolved& res) {
if (path.empty())
return -QUASI_EINVAL;
if (path.is_relative())
if (path.empty() || !path.string().starts_with("/"))
return -QUASI_EINVAL;
// if (path.is_relative())
// return -QUASI_EINVAL;
// on return:
// node - last element of the path (if exists)
@ -303,6 +303,7 @@ int QFS::Resolve(const fs::path& path, Resolved& res) {
res.mountpoint = mounted_partition;
res.parent = mntparent;
res.node = mntroot;
res.local_path = "/";
res.leaf = "/";
if (iter_path != "/")

View File

@ -84,11 +84,11 @@ inode_ptr Partition::GetInodeByFileno(fileno_t fileno) {
// DO NOT, AND I SWEAR D O N O T touch this function
// Debugging it is a royal PITA
int Partition::Resolve(fs::path& path, Resolved& res) {
if (path.empty())
if (path.empty() || !path.string().starts_with("/"))
return -QUASI_EINVAL;
if (path.is_relative())
return -QUASI_EBADF;
// if (path.is_relative())
// return -QUASI_EBADF;
if (path.string().size() >= 256)
return -QUASI_ENAMETOOLONG;

View File

@ -72,15 +72,20 @@ s32 QFS::OperationImpl::Open(const fs::path& path, int flags, u16 mode) {
int vio_status = 0;
if (part->IsHostMounted()) {
fs::path host_path_target{};
if (int hostpath_status = part->GetHostPath(host_path_target, res.local_path);
hostpath_status != 0)
return hostpath_status;
if (hio_status = qfs.hio_driver.Open(host_path_target, flags, mode); hio_status < 0)
// hosts operation must succeed in order to continue
return hio_status;
host_used = true;
if (nullptr == res.node || (res.node && !res.node->is_dir())) {
// if doesn't exist, creation/throwing becomes host's problem
// however we might want to open a dir for dirents, which would be suboptimal
fs::path host_path_target{};
if (int hostpath_status = part->GetHostPath(host_path_target, res.local_path);
hostpath_status != 0)
return hostpath_status;
if (hio_status = qfs.hio_driver.Open(host_path_target, flags, mode); hio_status < 0)
// hosts operation must succeed in order to continue
return hio_status;
host_used = true;
}
}
qfs.vio_driver.SetCtx(&res, host_used, nullptr);

View File

@ -552,7 +552,7 @@ static s64 GetDents(s32 fd, char* buf, u64 nbytes, s64* basep) {
s32 result = f->node->getdents(buf, nbytes, basep);
if (result < 0) {
ErrSceToPosix(result);
*__Error() = -result;
return -1;
}

View File

@ -88,38 +88,23 @@ Emulator::Emulator() {
Emulator::~Emulator() {}
void Emulator::LoadFilesystem(const std::string& id) {
const auto& mount_data_dir = Common::FS::GetUserPath(Common::FS::PathType::GameDataDir) / id;
if (!std::filesystem::exists(mount_data_dir)) {
std::filesystem::create_directory(mount_data_dir);
}
const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
if (std::filesystem::exists(mount_temp_dir)) {
// Temp folder should be cleared on each boot.
std::filesystem::remove_all(mount_temp_dir);
}
std::filesystem::create_directory(mount_temp_dir);
const auto& mount_download_dir =
Common::FS::GetUserPath(Common::FS::PathType::DownloadDir) / id;
if (!std::filesystem::exists(mount_download_dir)) {
std::filesystem::create_directory(mount_download_dir);
}
void Emulator::LoadFilesystem(const std::filesystem::path& game_folder) {
auto* qfs = Common::Singleton<qfs::QFS>::Instance();
qfs->Operation.MKDir("/app0", 0555);
qfs->Operation.MKDir("/hostapp", 0555);
qfs::partition_ptr partition_app0 = qfs::Partition::Create(game_folder, 0555, 512, 65536);
qfs->Mount("/app0", partition_app0, qfs::MountOptions::MOUNT_NOOPT);
qfs->Mount("/hostapp", partition_app0,
qfs::MountOptions::MOUNT_NOOPT | qfs::MountOptions::MOUNT_BIND);
qfs->Operation.Chmod("/", 0777);
qfs::partition_ptr partition_av_contents = qfs::Partition::Create("", 0775, 512, 16384);
qfs::partition_ptr partition_av_contents_photo = qfs::Partition::Create("", 0755, 4096, 32768);
qfs::partition_ptr partition_av_contents_thumbs = qfs::Partition::Create("", 0755, 4096, 32768);
qfs::partition_ptr partition_av_contents_video = qfs::Partition::Create("", 0755, 4096, 32768);
qfs::partition_ptr partition_data = qfs::Partition::Create(mount_data_dir, 0777, 4096, 32768);
qfs::partition_ptr partition_dev = qfs::Partition::Create("", 0755, 16384, 16384);
// no idea what are the block sizes for these 3
qfs::partition_ptr partition_download =
qfs::Partition::Create(mount_download_dir, 0777, 512, 65536);
qfs::partition_ptr partition_temp = qfs::Partition::Create(mount_temp_dir, 0777, 512, 16384);
qfs->Operation.MKDir("/av_contents", 0775);
qfs->Operation.MKDir("/av_contents/photo", 0755);
@ -138,13 +123,7 @@ void Emulator::LoadFilesystem(const std::string& id) {
qfs::MountOptions::MOUNT_RW);
qfs->Mount("/av_contents/video", partition_av_contents_video, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/data", partition_data, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/dev", partition_dev, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/download0", partition_download, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/temp", partition_temp, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/temp0", partition_temp,
qfs::MountOptions::MOUNT_RW | qfs::MountOptions::MOUNT_BIND);
//
// Setup /dev
@ -184,17 +163,11 @@ void Emulator::LoadFilesystem(const std::string& id) {
if (int fd_dev = qfs->Operation.Open("/dev/stderr", QUASI_O_WRONLY); fd_dev != 2)
LOG_CRITICAL(Kernel_Fs, "XDXDXD 2 != {}", fd_dev);
//
const auto& mount_captures_dir = Common::FS::GetUserPath(Common::FS::PathType::CapturesDir);
if (!std::filesystem::exists(mount_captures_dir)) {
std::filesystem::create_directory(mount_captures_dir);
}
VideoCore::SetOutputDir(mount_captures_dir, id);
qfs->SyncHost();
// qfs::printTree(qfs->GetRoot(), "/");
qfs::printTree(qfs->GetRoot(), "/");
return;
}
void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
@ -232,15 +205,10 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
// Certain games may use /hostapp as well such as CUSA001100
mnt->Mount(game_folder, "/hostapp", true);
auto* qfs = Common::Singleton<qfs::QFS>::Instance();
qfs->Operation.MKDir("/app0", 0555);
qfs::partition_ptr partition_app0 = qfs::Partition::Create(game_folder, 0555, 512, 65536);
qfs->Mount("/app0", partition_app0, qfs::MountOptions::MOUNT_NOOPT);
qfs->Mount("/hostapp", partition_app0,
qfs::MountOptions::MOUNT_NOOPT | qfs::MountOptions::MOUNT_BIND);
this->LoadFilesystem(game_folder);
// can't sync here, otherwise all mountpoints would need to be updated one by one
auto* qfs = Common::Singleton<qfs::QFS>::Instance();
std::filesystem::path param_sfo_path{};
{
qfs::Resolved res{};
@ -278,7 +246,41 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
psf_attributes.raw = *raw_attributes;
}
this->LoadFilesystem(id);
const auto& mount_captures_dir = Common::FS::GetUserPath(Common::FS::PathType::CapturesDir);
if (!std::filesystem::exists(mount_captures_dir)) {
std::filesystem::create_directory(mount_captures_dir);
}
VideoCore::SetOutputDir(mount_captures_dir, id);
const auto& mount_data_dir = Common::FS::GetUserPath(Common::FS::PathType::GameDataDir) / id;
if (!std::filesystem::exists(mount_data_dir)) {
std::filesystem::create_directory(mount_data_dir);
}
const auto& mount_download_dir =
Common::FS::GetUserPath(Common::FS::PathType::DownloadDir) / id;
if (!std::filesystem::exists(mount_download_dir)) {
std::filesystem::create_directory(mount_download_dir);
}
const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
if (std::filesystem::exists(mount_temp_dir)) {
// Temp folder should be cleared on each boot.
std::filesystem::remove_all(mount_temp_dir);
}
std::filesystem::create_directory(mount_temp_dir);
qfs::partition_ptr partition_data = qfs::Partition::Create(mount_data_dir, 0777, 4096, 32768);
qfs::partition_ptr partition_download =
qfs::Partition::Create(mount_download_dir, 0777, 512, 65536);
qfs::partition_ptr partition_temp = qfs::Partition::Create(mount_temp_dir, 0777, 512, 16384);
qfs->Mount("/data", partition_data, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/download0", partition_download, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/temp", partition_temp, qfs::MountOptions::MOUNT_RW);
qfs->Mount("/temp0", partition_temp,
qfs::MountOptions::MOUNT_RW | qfs::MountOptions::MOUNT_BIND);
qfs->SyncHost("/data");
qfs->SyncHost("/donwload0");
qfs->SyncHost("/temp");
qfs->SyncHost("/temp0");
Config::load(Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs) / (id + ".toml"),
true);
@ -419,14 +421,14 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
g_window = window.get();
const auto& mount_data_dir = Common::FS::GetUserPath(Common::FS::PathType::GameDataDir) / id;
// const auto& mount_data_dir = Common::FS::GetUserPath(Common::FS::PathType::GameDataDir) / id;
if (!std::filesystem::exists(mount_data_dir)) {
std::filesystem::create_directory(mount_data_dir);
}
mnt->Mount(mount_data_dir, "/data"); // should just exist, manually create with game serial
// Mounting temp folders
const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
//const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
if (std::filesystem::exists(mount_temp_dir)) {
// Temp folder should be cleared on each boot.
std::filesystem::remove_all(mount_temp_dir);
@ -435,14 +437,14 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
mnt->Mount(mount_temp_dir, "/temp0");
mnt->Mount(mount_temp_dir, "/temp");
const auto& mount_download_dir =
Common::FS::GetUserPath(Common::FS::PathType::DownloadDir) / id;
// const auto& mount_download_dir =
// Common::FS::GetUserPath(Common::FS::PathType::DownloadDir) / id;
if (!std::filesystem::exists(mount_download_dir)) {
std::filesystem::create_directory(mount_download_dir);
}
mnt->Mount(mount_download_dir, "/download0");
const auto& mount_captures_dir = Common::FS::GetUserPath(Common::FS::PathType::CapturesDir);
// const auto& mount_captures_dir = Common::FS::GetUserPath(Common::FS::PathType::CapturesDir);
if (!std::filesystem::exists(mount_captures_dir)) {
std::filesystem::create_directory(mount_captures_dir);
}

View File

@ -42,7 +42,7 @@ public:
private:
void LoadSystemModules(const std::string& game_serial);
void LoadFilesystem(const std::string& id);
void LoadFilesystem(const std::filesystem::path& game_folder);
Core::MemoryManager* memory;
Input::GameController* controller;