Merge pull request #14833 from JosJuice/state-nand-tas

IOS/FS: Fix loading savestate while TASing
This commit is contained in:
JosJuice
2026-09-20 22:30:42 +02:00
committed by GitHub

View File

@@ -139,12 +139,45 @@ ResultCode FileSystem::CreateFullPath(Uid uid, Gid gid, const std::string& path,
void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path)
{
const ResultCode delete_result = Delete(0, 0, directory_path);
if (delete_result != ResultCode::Success && delete_result != ResultCode::NotFound)
const auto delete_ = [this](const std::string& directory_path_) {
const ResultCode delete_result = Delete(0, 0, directory_path_);
if (delete_result != ResultCode::Success && delete_result != ResultCode::NotFound)
{
ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call Delete for {}: {}", directory_path_,
delete_result);
return false;
}
return true;
};
if (directory_path != "/")
{
ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call Delete: {}", delete_result);
p.SetVerifyMode();
return;
if (!delete_(directory_path))
{
p.SetVerifyMode();
return;
}
}
else
{
// Calling Delete for the root would return Invalid. Let's delete all children instead.
auto children = ReadDirectory(0, 0, directory_path);
if (!children)
{
ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call ReadDirectory for {}: {}", directory_path,
children.error());
p.SetVerifyMode();
return;
}
for (const std::string& child_name : children.value())
{
if (!delete_(directory_path + child_name))
{
p.SetVerifyMode();
return;
}
}
}
Metadata metadata{};
@@ -156,12 +189,29 @@ void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path)
p.Do(metadata.size);
p.Do(metadata.fst_index);
const ResultCode create_directory_result = CreateDirectory(
metadata.uid, metadata.gid, directory_path, metadata.attribute, metadata.modes);
if (create_directory_result != ResultCode::Success)
// Again here, calling CreateDirectory for the root would return Invalid.
// The root always exists, so we can skip creating it.
if (directory_path != "/")
{
ERROR_LOG_FMT(IOS_FS, "DoStateRead failed to call CreateDirectory: {}",
create_directory_result);
// 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,
create_directory_result);
p.SetVerifyMode();
return;
}
}
// 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;
}
@@ -182,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<u8, BUFFER_CHUNK_SIZE> buffer;
Result<FileHandle> 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;
@@ -213,7 +275,7 @@ void FileSystem::DoStateRead(PointerWrap& p, const std::string& directory_path)
Result<size_t> 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;
@@ -221,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;
}
@@ -241,7 +303,8 @@ void FileSystem::DoStateWriteOrMeasure(PointerWrap& p, const std::string& direct
const Result<Metadata> metadata = GetMetadata(0, 0, directory_path);
if (!metadata)
{
ERROR_LOG_FMT(IOS_FS, "DoStateWriteOrMeasure failed to call GetMetadata: {}", metadata.error());
ERROR_LOG_FMT(IOS_FS, "DoStateWriteOrMeasure failed to call GetMetadata for {}: {}",
directory_path, metadata.error());
p.SetVerifyMode();
return;
}
@@ -256,8 +319,8 @@ void FileSystem::DoStateWriteOrMeasure(PointerWrap& p, const std::string& direct
auto children = ReadDirectory(0, 0, directory_path);
if (!children)
{
ERROR_LOG_FMT(IOS_FS, "DoStateWriteOrMeasure failed to call ReadDirectory: {}",
children.error());
ERROR_LOG_FMT(IOS_FS, "DoStateWriteOrMeasure failed to call ReadDirectory for {}: {}",
directory_path, children.error());
p.SetVerifyMode();
return;
}