From 093d3abe95d14ca90cdd7ac9e57c5b76e89084d8 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 20 Sep 2026 11:59:28 +0200 Subject: [PATCH] IOS/FS: Fix loading savestate while TASing, part 2 When calling CreateDirectory for /wfs, we were passing a UID of 19, because that is the UID /wfs is supposed to have. However, CreateDirectory returns AccessDenied if we try to create a directory in the root using a UID other than 0. To fix this, let's use UID 0 to create the directory, and then change the UID and GID afterwards using SetMetadata. This is what the ESCore constructor does, which is the piece of code that normally creates /wfs. --- Source/Core/Core/IOS/FS/FileSystemCommon.cpp | 40 ++++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/IOS/FS/FileSystemCommon.cpp b/Source/Core/Core/IOS/FS/FileSystemCommon.cpp index 1d88e51f46..225084c177 100644 --- a/Source/Core/Core/IOS/FS/FileSystemCommon.cpp +++ b/Source/Core/Core/IOS/FS/FileSystemCommon.cpp @@ -193,8 +193,9 @@ void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path) // The root always exists, so we can skip creating it. if (directory_path != "/") { - const ResultCode create_directory_result = CreateDirectory( - metadata.uid, metadata.gid, directory_path, metadata.attribute, metadata.modes); + // UID 0 is used to avoid AccessDenied. + const ResultCode create_directory_result = + CreateDirectory(0, 0, directory_path, metadata.attribute, metadata.modes); if (create_directory_result != ResultCode::Success) { ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call CreateDirectory for {}: {}", directory_path, @@ -204,6 +205,17 @@ void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path) } } + // Change the UID and GID from 0 to the intended values. + const ResultCode set_metadata_result = SetMetadata(0, directory_path, metadata.uid, metadata.gid, + metadata.attribute, metadata.modes); + if (set_metadata_result != ResultCode::Success) + { + ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call SetMetadata for {}: {}", directory_path, + set_metadata_result); + p.SetVerifyMode(); + return; + } + // Now restore from the stream std::vector children; p.DoEachElement(children, [this, &directory_path](PointerWrap& p_, std::string& child_name) { @@ -220,22 +232,34 @@ void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path) if (child_metadata.is_file) { + // UID 0 is used to avoid AccessDenied. const ResultCode create_file_result = - CreateFile(child_metadata.uid, child_metadata.gid, child_path, child_metadata.attribute, - child_metadata.modes); + CreateFile(0, 0, child_path, child_metadata.attribute, child_metadata.modes); if (create_file_result != ResultCode::Success) { - ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call CreateFile for {}: {}", child_name, + ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call CreateFile for {}: {}", child_path, create_file_result); p_.SetVerifyMode(); return; } + // Change the UID and GID from 0 to the intended values. + const ResultCode set_metadata_result = + SetMetadata(0, child_path, child_metadata.uid, child_metadata.gid, + child_metadata.attribute, child_metadata.modes); + if (set_metadata_result != ResultCode::Success) + { + ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call SetMetadata for {}: {}", child_path, + set_metadata_result); + p_.SetVerifyMode(); + return; + } + std::array buffer; Result handle = OpenFile(0, 0, child_path, Mode::Write); if (!handle) { - ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call OpenFile for {}: {}", child_name, + ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call OpenFile for {}: {}", child_path, handle.error()); p_.SetVerifyMode(); return; @@ -251,7 +275,7 @@ void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path) Result write_result = handle->Write(buffer.data(), bytes_to_write); if (!write_result) { - ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call Write for {}: {}", child_name, + ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call Write for {}: {}", child_path, write_result.error()); p_.SetVerifyMode(); return; @@ -259,7 +283,7 @@ void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path) if (*write_result != bytes_to_write) { ERROR_LOG_FMT(IOS_FS, "DoStateRead tried to write {} bytes to {} but wrote {} bytes", - child_name, bytes_to_write, *write_result); + child_path, bytes_to_write, *write_result); p_.SetVerifyMode(); return; }