libkernel: Various filesystem fixes (#2868)

* Proper handling of whence 3 & 4

* Accurate directory handling in open

Directories can be opened, and can be created in open, these changes should handle that more accurately.

* Mount /app0 as read only

On real hardware, it's read only.

* Proper directory flag handling.

Even when directory is specified, it will still succeed to open non-directories.

* Check for read only directories

* Earlier ro check in posix_rmdir

Hardware tests suggest these checks are in a different order

* Clear temp folder on boot

My tests rely on this, and some games do too.
Two birds with one stone

* Clang

* Add missing DeleteHandle calls

Whoops

* Final flags adjustment in sceKernelOpen

All my current tests are now hardware accurate.

* Fix truncates

Host ftruncate consistently fails on EINVAL, I'll need to test if this issue affected Windows too.

* Windows hacks

Windows is more limiting about how folders are opened and things like that. For now, pretend these calls didn't error.
Also fixes compilation for Windows

* Final touch-ups

After expanding my test suite further, I found a couple more edge cases that needed addressing.
Bloodborne audio is still broken, I'll look into that soon.

* Remove hacky read-only behavior in posix_stat

Bloodborne apparently uses the mode parameter here when querying it's audio files, and the mode we returned led to it disabling audio entirely.

* Clang

* Cleaner code

* Combine fsync and sync flags

According to FreeBSD docs, the "sync" flag is synonymous with the fsync flag, and is only included to meet the POSIX spec.

* Log if any currently unhandled flags are encountered.

These are rare and probably not too important, but log a warning when they're seen.

* Update file_system.cpp

* Update file_system.cpp

* Clang

* Revert truncate fix

Using ftruncate works fine after moving the call to before the proper file opening code.

* Truncate before open

Open the file as read-write, then try truncating.
This fixes read | truncate flag behavior on Windows.

* Slightly adjust check for invalid flags

Any open call with invalid flags should return EINVAL, regardless of other errors parameters might cause.
This commit is contained in:
Stephen Miller 2025-05-01 06:47:43 -05:00 committed by GitHub
parent b0e4e87ff3
commit 6c39bf229c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 133 additions and 85 deletions

View file

@ -98,9 +98,9 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
// Applications expect to be run from /app0 so mount the file's parent path as app0.
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
mnt->Mount(game_folder, "/app0");
mnt->Mount(game_folder, "/app0", true);
// Certain games may use /hostapp as well such as CUSA001100
mnt->Mount(game_folder, "/hostapp");
mnt->Mount(game_folder, "/hostapp", true);
auto& game_info = Common::ElfInfo::Instance();
@ -231,11 +231,15 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
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;
if (!std::filesystem::exists(mount_temp_dir)) {
std::filesystem::create_directory(mount_temp_dir);
if (std::filesystem::exists(mount_temp_dir)) {
// Temp folder should be cleared on each boot.
std::filesystem::remove_all(mount_temp_dir);
}
mnt->Mount(mount_temp_dir, "/temp0"); // called in app_content ==> stat/mkdir
std::filesystem::create_directory(mount_temp_dir);
mnt->Mount(mount_temp_dir, "/temp0");
mnt->Mount(mount_temp_dir, "/temp");
const auto& mount_download_dir =