Merge pull request #14267 from jordan-woyak/std-expected

Common: Replace Result with std::expected.
This commit is contained in:
iwubcode
2026-01-17 22:33:15 -06:00
committed by GitHub
24 changed files with 164 additions and 197 deletions
-1
View File
@@ -127,7 +127,6 @@ add_library(common
QoSSession.h QoSSession.h
Random.cpp Random.cpp
Random.h Random.h
Result.h
ScopeGuard.h ScopeGuard.h
SDCardUtil.cpp SDCardUtil.cpp
SDCardUtil.h SDCardUtil.h
-36
View File
@@ -1,36 +0,0 @@
// Copyright 2018 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <variant>
namespace Common
{
template <typename Expected, typename Unexpected>
class Result final
{
public:
constexpr Result(const Expected& value) : m_variant{value} {}
constexpr Result(Expected&& value) : m_variant{std::move(value)} {}
constexpr Result(const Unexpected& value) : m_variant{value} {}
constexpr Result(Unexpected&& value) : m_variant{std::move(value)} {}
constexpr explicit operator bool() const { return Succeeded(); }
constexpr bool Succeeded() const { return std::holds_alternative<Expected>(m_variant); }
// Must only be called when Succeeded() returns true.
constexpr const Expected& operator*() const { return std::get<Expected>(m_variant); }
constexpr const Expected* operator->() const { return &std::get<Expected>(m_variant); }
constexpr Expected& operator*() { return std::get<Expected>(m_variant); }
constexpr Expected* operator->() { return &std::get<Expected>(m_variant); }
// Must only be called when Succeeded() returns false.
constexpr Unexpected& Error() { return std::get<Unexpected>(m_variant); }
constexpr const Unexpected& Error() const { return std::get<Unexpected>(m_variant); }
private:
std::variant<Expected, Unexpected> m_variant;
};
} // namespace Common
+3 -3
View File
@@ -703,13 +703,13 @@ void UpdateStateFlags(std::function<void(StateFlags*)> update_function)
StateFlags state{}; StateFlags state{};
if (file->GetStatus()->size == sizeof(StateFlags)) if (file->GetStatus()->size == sizeof(StateFlags))
file->Read(&state, 1); (void)file->Read(&state, 1);
update_function(&state); update_function(&state);
state.UpdateChecksum(); state.UpdateChecksum();
file->Seek(0, IOS::HLE::FS::SeekMode::Set); (void)file->Seek(0, IOS::HLE::FS::SeekMode::Set);
file->Write(&state, 1); (void)file->Write(&state, 1);
} }
void CreateSystemMenuTitleDirs() void CreateSystemMenuTitleDirs()
+1 -1
View File
@@ -526,7 +526,7 @@ static void WriteEmptyPlayRecord()
if (!playrec_file) if (!playrec_file)
return; return;
std::vector<u8> empty_record(0x80); std::vector<u8> empty_record(0x80);
playrec_file->Write(empty_record.data(), empty_record.size()); (void)playrec_file->Write(empty_record.data(), empty_record.size());
} }
// __________________________________________________________________________________________________ // __________________________________________________________________________________________________
+5 -5
View File
@@ -3,13 +3,13 @@
#include "Core/CheatGeneration.h" #include "Core/CheatGeneration.h"
#include <expected>
#include <vector> #include <vector>
#include <fmt/format.h> #include <fmt/format.h>
#include "Common/Align.h" #include "Common/Align.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Result.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/ActionReplay.h" #include "Core/ActionReplay.h"
@@ -52,20 +52,20 @@ static std::vector<ActionReplay::AREntry> ResultToAREntries(u32 addr, const Chea
return codes; return codes;
} }
Common::Result<ActionReplay::ARCode, Cheats::GenerateActionReplayCodeErrorCode> std::expected<ActionReplay::ARCode, Cheats::GenerateActionReplayCodeErrorCode>
Cheats::GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index) Cheats::GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index)
{ {
if (index >= session.GetResultCount()) if (index >= session.GetResultCount())
return Cheats::GenerateActionReplayCodeErrorCode::IndexOutOfRange; return std::unexpected{Cheats::GenerateActionReplayCodeErrorCode::IndexOutOfRange};
if (session.GetResultValueState(index) != Cheats::SearchResultValueState::ValueFromVirtualMemory) if (session.GetResultValueState(index) != Cheats::SearchResultValueState::ValueFromVirtualMemory)
return Cheats::GenerateActionReplayCodeErrorCode::NotVirtualMemory; return std::unexpected{Cheats::GenerateActionReplayCodeErrorCode::NotVirtualMemory};
u32 address = session.GetResultAddress(index); u32 address = session.GetResultAddress(index);
// check if the address is actually addressable by the ActionReplay system // check if the address is actually addressable by the ActionReplay system
if (((address & 0x01ff'ffffu) | 0x8000'0000u) != address) if (((address & 0x01ff'ffffu) | 0x8000'0000u) != address)
return Cheats::GenerateActionReplayCodeErrorCode::InvalidAddress; return std::unexpected{Cheats::GenerateActionReplayCodeErrorCode::InvalidAddress};
ActionReplay::ARCode ar_code; ActionReplay::ARCode ar_code;
ar_code.enabled = true; ar_code.enabled = true;
+2 -2
View File
@@ -3,7 +3,7 @@
#pragma once #pragma once
#include "Common/Result.h" #include <expected>
#include "Core/ActionReplay.h" #include "Core/ActionReplay.h"
@@ -18,6 +18,6 @@ enum class GenerateActionReplayCodeErrorCode
InvalidAddress, InvalidAddress,
}; };
Common::Result<ActionReplay::ARCode, GenerateActionReplayCodeErrorCode> std::expected<ActionReplay::ARCode, GenerateActionReplayCodeErrorCode>
GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index); GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index);
} // namespace Cheats } // namespace Cheats
+13 -12
View File
@@ -4,6 +4,7 @@
#include "Core/CheatSearch.h" #include "Core/CheatSearch.h"
#include <bit> #include <bit>
#include <expected>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <optional> #include <optional>
@@ -113,19 +114,19 @@ auto Cheats::NewSearch(const Core::CPUThreadGuard& guard,
const std::vector<Cheats::MemoryRange>& memory_ranges, const std::vector<Cheats::MemoryRange>& memory_ranges,
PowerPC::RequestedAddressSpace address_space, bool aligned, PowerPC::RequestedAddressSpace address_space, bool aligned,
const std::function<bool(const T& value)>& validator) const std::function<bool(const T& value)>& validator)
-> Common::Result<std::vector<SearchResult<T>>, SearchErrorCode> -> std::expected<std::vector<SearchResult<T>>, SearchErrorCode>
{ {
if (AchievementManager::GetInstance().IsHardcoreModeActive()) if (AchievementManager::GetInstance().IsHardcoreModeActive())
return Cheats::SearchErrorCode::DisabledInHardcoreMode; return std::unexpected{Cheats::SearchErrorCode::DisabledInHardcoreMode};
auto& system = guard.GetSystem(); auto& system = guard.GetSystem();
std::vector<Cheats::SearchResult<T>> results; std::vector<Cheats::SearchResult<T>> results;
const Core::State core_state = Core::GetState(system); const Core::State core_state = Core::GetState(system);
if (core_state != Core::State::Running && core_state != Core::State::Paused) if (core_state != Core::State::Running && core_state != Core::State::Paused)
return Cheats::SearchErrorCode::NoEmulationActive; return std::unexpected{Cheats::SearchErrorCode::NoEmulationActive};
const auto& ppc_state = system.GetPPCState(); const auto& ppc_state = system.GetPPCState();
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR) if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR)
return Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible; return std::unexpected{Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible};
for (const Cheats::MemoryRange& range : memory_ranges) for (const Cheats::MemoryRange& range : memory_ranges)
{ {
@@ -166,19 +167,19 @@ auto Cheats::NextSearch(
const Core::CPUThreadGuard& guard, const std::vector<Cheats::SearchResult<T>>& previous_results, const Core::CPUThreadGuard& guard, const std::vector<Cheats::SearchResult<T>>& previous_results,
PowerPC::RequestedAddressSpace address_space, PowerPC::RequestedAddressSpace address_space,
const std::function<bool(const T& new_value, const T& old_value)>& validator) const std::function<bool(const T& new_value, const T& old_value)>& validator)
-> Common::Result<std::vector<SearchResult<T>>, SearchErrorCode> -> std::expected<std::vector<SearchResult<T>>, SearchErrorCode>
{ {
if (AchievementManager::GetInstance().IsHardcoreModeActive()) if (AchievementManager::GetInstance().IsHardcoreModeActive())
return Cheats::SearchErrorCode::DisabledInHardcoreMode; return std::unexpected{Cheats::SearchErrorCode::DisabledInHardcoreMode};
auto& system = guard.GetSystem(); auto& system = guard.GetSystem();
std::vector<Cheats::SearchResult<T>> results; std::vector<Cheats::SearchResult<T>> results;
const Core::State core_state = Core::GetState(system); const Core::State core_state = Core::GetState(system);
if (core_state != Core::State::Running && core_state != Core::State::Paused) if (core_state != Core::State::Running && core_state != Core::State::Paused)
return Cheats::SearchErrorCode::NoEmulationActive; return std::unexpected{Cheats::SearchErrorCode::NoEmulationActive};
const auto& ppc_state = system.GetPPCState(); const auto& ppc_state = system.GetPPCState();
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR) if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR)
return Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible; return std::unexpected{Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible};
for (const auto& previous_result : previous_results) for (const auto& previous_result : previous_results)
{ {
@@ -335,8 +336,8 @@ Cheats::SearchErrorCode Cheats::CheatSearchSession<T>::RunSearch(const Core::CPU
{ {
if (AchievementManager::GetInstance().IsHardcoreModeActive()) if (AchievementManager::GetInstance().IsHardcoreModeActive())
return Cheats::SearchErrorCode::DisabledInHardcoreMode; return Cheats::SearchErrorCode::DisabledInHardcoreMode;
Common::Result<std::vector<SearchResult<T>>, SearchErrorCode> result = std::expected<std::vector<SearchResult<T>>, SearchErrorCode> result =
Cheats::SearchErrorCode::InvalidParameters; std::unexpected{Cheats::SearchErrorCode::InvalidParameters};
if (m_filter_type == FilterType::CompareAgainstSpecificValue) if (m_filter_type == FilterType::CompareAgainstSpecificValue)
{ {
if (!m_value) if (!m_value)
@@ -376,14 +377,14 @@ Cheats::SearchErrorCode Cheats::CheatSearchSession<T>::RunSearch(const Core::CPU
} }
} }
if (result.Succeeded()) if (result.has_value())
{ {
m_search_results = std::move(*result); m_search_results = std::move(*result);
m_first_search_done = true; m_first_search_done = true;
return Cheats::SearchErrorCode::Success; return Cheats::SearchErrorCode::Success;
} }
return result.Error(); return result.error();
} }
template <typename T> template <typename T>
+3 -3
View File
@@ -3,6 +3,7 @@
#pragma once #pragma once
#include <expected>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <optional> #include <optional>
@@ -12,7 +13,6 @@
#include <vector> #include <vector>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Result.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
namespace Core namespace Core
@@ -116,7 +116,7 @@ std::vector<u8> GetValueAsByteVector(const SearchValue& value);
// Do a new search across the given memory region in the given address space, only keeping values // Do a new search across the given memory region in the given address space, only keeping values
// for which the given validator returns true. // for which the given validator returns true.
template <typename T> template <typename T>
Common::Result<std::vector<SearchResult<T>>, SearchErrorCode> std::expected<std::vector<SearchResult<T>>, SearchErrorCode>
NewSearch(const Core::CPUThreadGuard& guard, const std::vector<MemoryRange>& memory_ranges, NewSearch(const Core::CPUThreadGuard& guard, const std::vector<MemoryRange>& memory_ranges,
PowerPC::RequestedAddressSpace address_space, bool aligned, PowerPC::RequestedAddressSpace address_space, bool aligned,
const std::function<bool(const T& value)>& validator); const std::function<bool(const T& value)>& validator);
@@ -124,7 +124,7 @@ NewSearch(const Core::CPUThreadGuard& guard, const std::vector<MemoryRange>& mem
// Refresh the values for the given results in the given address space, only keeping values for // Refresh the values for the given results in the given address space, only keeping values for
// which the given validator returns true. // which the given validator returns true.
template <typename T> template <typename T>
Common::Result<std::vector<SearchResult<T>>, SearchErrorCode> std::expected<std::vector<SearchResult<T>>, SearchErrorCode>
NextSearch(const Core::CPUThreadGuard& guard, const std::vector<SearchResult<T>>& previous_results, NextSearch(const Core::CPUThreadGuard& guard, const std::vector<SearchResult<T>>& previous_results,
PowerPC::RequestedAddressSpace address_space, PowerPC::RequestedAddressSpace address_space,
const std::function<bool(const T& new_value, const T& old_value)>& validator); const std::function<bool(const T& new_value, const T& old_value)>& validator);
+3 -3
View File
@@ -161,7 +161,7 @@ void ESDevice::FinishInit()
if (launch_file) if (launch_file)
{ {
u64 id; u64 id;
if (launch_file->Read(&id, 1).Succeeded()) if (launch_file->Read(&id, 1).has_value())
pending_launch_title_id = id; pending_launch_title_id = id;
} }
} }
@@ -811,7 +811,7 @@ static ReturnCode WriteTmdForDiVerify(FS::FileSystem* fs, const ES::TMDReader& t
{ {
const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, internal_modes); const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, internal_modes);
if (!file) if (!file)
return FS::ConvertResult(file.Error()); return FS::ConvertResult(file.error());
if (!file->Write(tmd.GetBytes().data(), tmd.GetBytes().size())) if (!file->Write(tmd.GetBytes().data(), tmd.GetBytes().size()))
return ES_EIO; return ES_EIO;
} }
@@ -1039,7 +1039,7 @@ ReturnCode ESCore::ReadCertStore(std::vector<u8>* buffer) const
const auto store_file = const auto store_file =
m_ios.GetFS()->OpenFile(PID_KERNEL, PID_KERNEL, CERT_STORE_PATH, FS::Mode::Read); m_ios.GetFS()->OpenFile(PID_KERNEL, PID_KERNEL, CERT_STORE_PATH, FS::Mode::Read);
if (!store_file) if (!store_file)
return FS::ConvertResult(store_file.Error()); return FS::ConvertResult(store_file.error());
buffer->resize(store_file->GetStatus()->size); buffer->resize(store_file->GetStatus()->size);
if (!store_file->Read(buffer->data(), buffer->size())) if (!store_file->Read(buffer->data(), buffer->size()))
+3 -3
View File
@@ -198,7 +198,7 @@ ESCore::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
// Check whether the content file exists. // Check whether the content file exists.
const auto file = fs->OpenFile(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read); const auto file = fs->OpenFile(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read);
if (!file.Succeeded()) if (!file.has_value())
return false; return false;
// If content hash checks are disabled, all we have to do is check for existence. // If content hash checks are disabled, all we have to do is check for existence.
@@ -237,7 +237,7 @@ static bool DeleteDirectoriesIfEmpty(FS::FileSystem* fs, const std::string& path
{ {
const auto directory = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, path.substr(0, position)); const auto directory = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, path.substr(0, position));
if ((directory && directory->empty()) || if ((directory && directory->empty()) ||
(!directory && directory.Error() != FS::ResultCode::NotFound)) (!directory && directory.error() != FS::ResultCode::NotFound))
{ {
if (fs->Delete(PID_KERNEL, PID_KERNEL, path.substr(0, position)) != FS::ResultCode::Success) if (fs->Delete(PID_KERNEL, PID_KERNEL, path.substr(0, position)) != FS::ResultCode::Success)
return false; return false;
@@ -268,7 +268,7 @@ bool ESCore::CreateTitleDirectories(u64 title_id, u16 group_id) const
const std::string data_dir = Common::GetTitleDataPath(title_id); const std::string data_dir = Common::GetTitleDataPath(title_id);
const auto data_dir_contents = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, data_dir); const auto data_dir_contents = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, data_dir);
if (!data_dir_contents && (data_dir_contents.Error() != FS::ResultCode::NotFound || if (!data_dir_contents && (data_dir_contents.error() != FS::ResultCode::NotFound ||
fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0, fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0,
data_dir_modes) != FS::ResultCode::Success)) data_dir_modes) != FS::ResultCode::Success))
{ {
+3 -3
View File
@@ -33,7 +33,7 @@ static ReturnCode WriteTicket(FS::FileSystem* fs, const ES::TicketReader& ticket
fs->CreateFullPath(PID_KERNEL, PID_KERNEL, path, 0, ticket_modes); fs->CreateFullPath(PID_KERNEL, PID_KERNEL, path, 0, ticket_modes);
const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, path, ticket_modes); const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, path, ticket_modes);
if (!file) if (!file)
return FS::ConvertResult(file.Error()); return FS::ConvertResult(file.error());
const std::vector<u8>& raw_ticket = ticket.GetBytes(); const std::vector<u8>& raw_ticket = ticket.GetBytes();
return file->Write(raw_ticket.data(), raw_ticket.size()) ? IPC_SUCCESS : ES_EIO; return file->Write(raw_ticket.data(), raw_ticket.size()) ? IPC_SUCCESS : ES_EIO;
@@ -472,7 +472,7 @@ static bool HasAllRequiredContents(Kernel& ios, const ES::TMDReader& tmd)
// Note: the import hasn't been finalised yet, so the whole title directory // Note: the import hasn't been finalised yet, so the whole title directory
// is still in /import, not /title. // is still in /import, not /title.
const std::string path = GetImportContentPath(title_id, content.id); const std::string path = GetImportContentPath(title_id, content.id);
return ios.GetFS()->GetMetadata(PID_KERNEL, PID_KERNEL, path).Succeeded(); return ios.GetFS()->GetMetadata(PID_KERNEL, PID_KERNEL, path).has_value();
}); });
} }
@@ -640,7 +640,7 @@ ReturnCode ESCore::DeleteTitleContent(u64 title_id) const
const std::string content_dir = Common::GetTitleContentPath(title_id); const std::string content_dir = Common::GetTitleContentPath(title_id);
const auto files = m_ios.GetFS()->ReadDirectory(PID_KERNEL, PID_KERNEL, content_dir); const auto files = m_ios.GetFS()->ReadDirectory(PID_KERNEL, PID_KERNEL, content_dir);
if (!files) if (!files)
return FS::ConvertResult(files.Error()); return FS::ConvertResult(files.error());
for (const std::string& file_name : *files) for (const std::string& file_name : *files)
{ {
+5 -5
View File
@@ -3,6 +3,7 @@
#pragma once #pragma once
#include <expected>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
@@ -15,7 +16,6 @@
#endif #endif
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Result.h"
class PointerWrap; class PointerWrap;
@@ -49,7 +49,7 @@ enum class ResultCode
}; };
template <typename T> template <typename T>
using Result = Common::Result<T, ResultCode>; using Result = std::expected<T, ResultCode>;
using Uid = u32; using Uid = u32;
using Gid = u16; using Gid = u16;
@@ -289,9 +289,9 @@ Result<size_t> FileHandle::Read(T* ptr, size_t count) const
const Result<u32> bytes = m_fs->ReadBytesFromFile(*m_fd, reinterpret_cast<u8*>(ptr), const Result<u32> bytes = m_fs->ReadBytesFromFile(*m_fd, reinterpret_cast<u8*>(ptr),
static_cast<u32>(sizeof(T) * count)); static_cast<u32>(sizeof(T) * count));
if (!bytes) if (!bytes)
return bytes.Error(); return bytes;
if (*bytes != sizeof(T) * count) if (*bytes != sizeof(T) * count)
return ResultCode::ShortRead; return std::unexpected{ResultCode::ShortRead};
return count; return count;
} }
@@ -301,7 +301,7 @@ Result<size_t> FileHandle::Write(const T* ptr, size_t count) const
const auto result = m_fs->WriteBytesToFile(*m_fd, reinterpret_cast<const u8*>(ptr), const auto result = m_fs->WriteBytesToFile(*m_fd, reinterpret_cast<const u8*>(ptr),
static_cast<u32>(sizeof(T) * count)); static_cast<u32>(sizeof(T) * count));
if (!result) if (!result)
return result.Error(); return result;
return count; return count;
} }
+4 -3
View File
@@ -4,6 +4,7 @@
#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/FS/FileSystem.h"
#include <algorithm> #include <algorithm>
#include <expected>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
@@ -100,7 +101,7 @@ Result<FileHandle> FileSystem::CreateAndOpenFile(Uid uid, Gid gid, const std::st
const ResultCode result = CreateFile(uid, gid, path, 0, modes); const ResultCode result = CreateFile(uid, gid, path, 0, modes);
if (result != ResultCode::Success) if (result != ResultCode::Success)
return result; return std::unexpected{result};
return OpenFile(uid, gid, path, Mode::ReadWrite); return OpenFile(uid, gid, path, Mode::ReadWrite);
} }
@@ -117,8 +118,8 @@ ResultCode FileSystem::CreateFullPath(Uid uid, Gid gid, const std::string& path,
const std::string subpath = path.substr(0, position); const std::string subpath = path.substr(0, position);
const Result<Metadata> metadata = GetMetadata(uid, gid, subpath); const Result<Metadata> metadata = GetMetadata(uid, gid, subpath);
if (!metadata && metadata.Error() != ResultCode::NotFound) if (!metadata && metadata.error() != ResultCode::NotFound)
return metadata.Error(); return metadata.error();
if (metadata && metadata->is_file) if (metadata && metadata->is_file)
return ResultCode::Invalid; return ResultCode::Invalid;
+17 -17
View File
@@ -5,13 +5,13 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <expected>
#include <string_view> #include <string_view>
#include <utility> #include <utility>
#include <fmt/format.h> #include <fmt/format.h>
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/StringUtil.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
@@ -126,7 +126,7 @@ static void LogResult(ResultCode code, fmt::format_string<Args...> format, Args&
template <typename T, typename... Args> template <typename T, typename... Args>
static void LogResult(const Result<T>& result, fmt::format_string<Args...> format, Args&&... args) static void LogResult(const Result<T>& result, fmt::format_string<Args...> format, Args&&... args)
{ {
const auto result_code = result.Succeeded() ? ResultCode::Success : result.Error(); const auto result_code = result.has_value() ? ResultCode::Success : result.error();
LogResult(result_code, format, std::forward<Args>(args)...); LogResult(result_code, format, std::forward<Args>(args)...);
} }
@@ -202,7 +202,7 @@ FSCore::ScopedFd FSCore::Open(FS::Uid uid, FS::Gid gid, const std::string& path,
auto backend_fd = m_ios.GetFS()->OpenFile(uid, gid, path, mode); auto backend_fd = m_ios.GetFS()->OpenFile(uid, gid, path, mode);
LogResult(backend_fd, "OpenFile({})", path); LogResult(backend_fd, "OpenFile({})", path);
if (!backend_fd) if (!backend_fd)
return {this, ConvertResult(backend_fd.Error()), ticks}; return {this, ConvertResult(backend_fd.error()), ticks};
auto& handle = m_fd_map[fd] = {gid, uid, backend_fd->Release()}; auto& handle = m_fd_map[fd] = {gid, uid, backend_fd->Release()};
std::strncpy(handle.name.data(), path.c_str(), handle.name.size()); std::strncpy(handle.name.data(), path.c_str(), handle.name.size());
@@ -347,7 +347,7 @@ s32 FSCore::Read(u64 fd, u8* data, u32 size, std::optional<u32> ipc_buffer_addr,
LogResult(result, "Read({}, 0x{:08x}, {})", handle.name.data(), *ipc_buffer_addr, size); LogResult(result, "Read({}, 0x{:08x}, {})", handle.name.data(), *ipc_buffer_addr, size);
if (!result) if (!result)
return ConvertResult(result.Error()); return ConvertResult(result.error());
return *result; return *result;
} }
@@ -378,7 +378,7 @@ s32 FSCore::Write(u64 fd, const u8* data, u32 size, std::optional<u32> ipc_buffe
LogResult(result, "Write({}, 0x{:08x}, {})", handle.name.data(), *ipc_buffer_addr, size); LogResult(result, "Write({}, 0x{:08x}, {})", handle.name.data(), *ipc_buffer_addr, size);
if (!result) if (!result)
return ConvertResult(result.Error()); return ConvertResult(result.error());
return *result; return *result;
} }
@@ -401,7 +401,7 @@ s32 FSCore::Seek(u64 fd, u32 offset, FS::SeekMode mode, Ticks ticks)
const Result<u32> result = m_ios.GetFS()->SeekFile(handle.fs_fd, offset, mode); const Result<u32> result = m_ios.GetFS()->SeekFile(handle.fs_fd, offset, mode);
LogResult(result, "Seek({}, 0x{:08x}, {})", handle.name.data(), offset, static_cast<int>(mode)); LogResult(result, "Seek({}, 0x{:08x}, {})", handle.name.data(), offset, static_cast<int>(mode));
if (!result) if (!result)
return ConvertResult(result.Error()); return ConvertResult(result.error());
return *result; return *result;
} }
@@ -437,7 +437,7 @@ template <typename T>
static Result<T> GetParams(Memory::MemoryManager& memory, const IOCtlRequest& request) static Result<T> GetParams(Memory::MemoryManager& memory, const IOCtlRequest& request)
{ {
if (request.buffer_in_size < sizeof(T)) if (request.buffer_in_size < sizeof(T))
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
T params; T params;
memory.CopyFromEmu(&params, request.buffer_in, sizeof(params)); memory.CopyFromEmu(&params, request.buffer_in, sizeof(params));
@@ -513,7 +513,7 @@ IPCReply FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)
const Result<NandStats> stats = m_ios.GetFS()->GetNandStats(); const Result<NandStats> stats = m_ios.GetFS()->GetNandStats();
LogResult(stats, "GetNandStats"); LogResult(stats, "GetNandStats");
if (!stats) if (!stats)
return IPCReply(ConvertResult(stats.Error())); return IPCReply(ConvertResult(stats.error()));
auto& system = GetSystem(); auto& system = GetSystem();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
@@ -534,7 +534,7 @@ IPCReply FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequest& req
{ {
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request); const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params) if (!params)
return GetFSReply(ConvertResult(params.Error())); return GetFSReply(ConvertResult(params.error()));
const ResultCode result = m_ios.GetFS()->CreateDirectory(handle.uid, handle.gid, params->path, const ResultCode result = m_ios.GetFS()->CreateDirectory(handle.uid, handle.gid, params->path,
params->attribute, params->modes); params->attribute, params->modes);
@@ -579,7 +579,7 @@ IPCReply FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& requ
m_ios.GetFS()->ReadDirectory(handle.uid, handle.gid, directory); m_ios.GetFS()->ReadDirectory(handle.uid, handle.gid, directory);
LogResult(list, "ReadDirectory({})", directory); LogResult(list, "ReadDirectory({})", directory);
if (!list) if (!list)
return GetFSReply(ConvertResult(list.Error())); return GetFSReply(ConvertResult(list.error()));
if (!file_list_address) if (!file_list_address)
{ {
@@ -603,7 +603,7 @@ IPCReply FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest& reques
{ {
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request); const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params) if (!params)
return GetFSReply(ConvertResult(params.Error())); return GetFSReply(ConvertResult(params.error()));
const ResultCode result = m_ios.GetFS()->SetMetadata( const ResultCode result = m_ios.GetFS()->SetMetadata(
handle.uid, params->path, params->uid, params->gid, params->attribute, params->modes); handle.uid, params->path, params->uid, params->gid, params->attribute, params->modes);
@@ -624,7 +624,7 @@ IPCReply FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& reques
const Result<Metadata> metadata = m_ios.GetFS()->GetMetadata(handle.uid, handle.gid, path); const Result<Metadata> metadata = m_ios.GetFS()->GetMetadata(handle.uid, handle.gid, path);
LogResult(metadata, "GetMetadata({})", path); LogResult(metadata, "GetMetadata({})", path);
if (!metadata) if (!metadata)
return GetFSReply(ConvertResult(metadata.Error()), ticks); return GetFSReply(ConvertResult(metadata.error()), ticks);
// Yes, the other members aren't copied at all. Actually, IOS does not even memset // Yes, the other members aren't copied at all. Actually, IOS does not even memset
// the struct at all, which means uninitialised bytes from the stack are returned. // the struct at all, which means uninitialised bytes from the stack are returned.
@@ -703,7 +703,7 @@ IPCReply FSDevice::CreateFile(const Handle& handle, const IOCtlRequest& request)
{ {
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request); const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params) if (!params)
return GetFSReply(ConvertResult(params.Error())); return GetFSReply(ConvertResult(params.error()));
return MakeIPCReply([&](Ticks ticks) { return MakeIPCReply([&](Ticks ticks) {
return ConvertResult( return ConvertResult(
m_core.CreateFile(handle.uid, handle.gid, params->path, params->attribute, params->modes)); m_core.CreateFile(handle.uid, handle.gid, params->path, params->attribute, params->modes));
@@ -714,7 +714,7 @@ IPCReply FSDevice::SetFileVersionControl(const Handle& handle, const IOCtlReques
{ {
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request); const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params) if (!params)
return GetFSReply(ConvertResult(params.Error())); return GetFSReply(ConvertResult(params.error()));
// FS_SetFileVersionControl(ctx->uid, params->path, params->attribute) // FS_SetFileVersionControl(ctx->uid, params->path, params->attribute)
ERROR_LOG_FMT(IOS_FS, "SetFileVersionControl({}, {:#x}): Stubbed", params->path, ERROR_LOG_FMT(IOS_FS, "SetFileVersionControl({}, {:#x}): Stubbed", params->path,
@@ -730,7 +730,7 @@ IPCReply FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& reques
return MakeIPCReply([&](Ticks ticks) { return MakeIPCReply([&](Ticks ticks) {
const Result<FileStatus> status = m_core.GetFileStatus(request.fd, ticks); const Result<FileStatus> status = m_core.GetFileStatus(request.fd, ticks);
if (!status) if (!status)
return ConvertResult(status.Error()); return ConvertResult(status.error());
auto& system = GetSystem(); auto& system = GetSystem();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
@@ -748,7 +748,7 @@ FS::Result<FS::FileStatus> FSCore::GetFileStatus(u64 fd, Ticks ticks)
ticks.Add(IPC_OVERHEAD_TICKS); ticks.Add(IPC_OVERHEAD_TICKS);
const auto& handle = m_fd_map[fd]; const auto& handle = m_fd_map[fd];
if (handle.fs_fd == INVALID_FD) if (handle.fs_fd == INVALID_FD)
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
auto status = m_ios.GetFS()->GetFileStatus(handle.fs_fd); auto status = m_ios.GetFS()->GetFileStatus(handle.fs_fd);
LogResult(status, "GetFileStatus({})", handle.name.data()); LogResult(status, "GetFileStatus({})", handle.name.data());
@@ -770,7 +770,7 @@ IPCReply FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& request)
const Result<DirectoryStats> stats = m_ios.GetFS()->GetDirectoryStats(directory); const Result<DirectoryStats> stats = m_ios.GetFS()->GetDirectoryStats(directory);
LogResult(stats, "GetDirectoryStats({})", directory); LogResult(stats, "GetDirectoryStats({})", directory);
if (!stats) if (!stats)
return GetFSReply(ConvertResult(stats.Error())); return GetFSReply(ConvertResult(stats.error()));
memory.Write_U32(stats->used_clusters, request.io_vectors[0].address); memory.Write_U32(stats->used_clusters, request.io_vectors[0].address);
memory.Write_U32(stats->used_inodes, request.io_vectors[1].address); memory.Write_U32(stats->used_inodes, request.io_vectors[1].address);
+14 -14
View File
@@ -4,7 +4,7 @@
#include "Core/IOS/FS/HostBackend/FS.h" #include "Core/IOS/FS/HostBackend/FS.h"
#include <algorithm> #include <algorithm>
#include <cmath> #include <expected>
#include <optional> #include <optional>
#include <string_view> #include <string_view>
#include <type_traits> #include <type_traits>
@@ -652,17 +652,17 @@ Result<std::vector<std::string>> HostFileSystem::ReadDirectory(Uid uid, Gid gid,
const std::string& path) const std::string& path)
{ {
if (!IsValidPath(path)) if (!IsValidPath(path))
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
const FstEntry* entry = GetFstEntryForPath(path); const FstEntry* entry = GetFstEntryForPath(path);
if (!entry) if (!entry)
return ResultCode::NotFound; return std::unexpected{ResultCode::NotFound};
if (!entry->CheckPermission(uid, gid, Mode::Read)) if (!entry->CheckPermission(uid, gid, Mode::Read))
return ResultCode::AccessDenied; return std::unexpected{ResultCode::AccessDenied};
if (entry->data.is_file) if (entry->data.is_file)
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
const std::string host_path = BuildFilename(path).host_path; const std::string host_path = BuildFilename(path).host_path;
File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false); File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false);
@@ -712,19 +712,19 @@ Result<Metadata> HostFileSystem::GetMetadata(Uid uid, Gid gid, const std::string
else else
{ {
if (!IsValidNonRootPath(path)) if (!IsValidNonRootPath(path))
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
const auto split_path = SplitPathAndBasename(path); const auto split_path = SplitPathAndBasename(path);
const FstEntry* parent = GetFstEntryForPath(split_path.parent); const FstEntry* parent = GetFstEntryForPath(split_path.parent);
if (!parent) if (!parent)
return ResultCode::NotFound; return std::unexpected{ResultCode::NotFound};
if (!parent->CheckPermission(uid, gid, Mode::Read)) if (!parent->CheckPermission(uid, gid, Mode::Read))
return ResultCode::AccessDenied; return std::unexpected{ResultCode::AccessDenied};
entry = GetFstEntryForPath(path); entry = GetFstEntryForPath(path);
} }
if (!entry) if (!entry)
return ResultCode::NotFound; return std::unexpected{ResultCode::NotFound};
Metadata metadata = entry->data; Metadata metadata = entry->data;
metadata.size = File::GetSize(BuildFilename(path).host_path); metadata.size = File::GetSize(BuildFilename(path).host_path);
@@ -780,7 +780,7 @@ Result<NandStats> HostFileSystem::GetNandStats()
{ {
const auto root_stats = GetDirectoryStats("/"); const auto root_stats = GetDirectoryStats("/");
if (!root_stats) if (!root_stats)
return root_stats.Error(); // TODO: is this right? can this fail on hardware? return std::unexpected{root_stats.error()}; // TODO: is this right? can this fail on hardware?
NandStats stats{}; NandStats stats{};
stats.cluster_size = CLUSTER_SIZE; stats.cluster_size = CLUSTER_SIZE;
@@ -798,7 +798,7 @@ Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_
{ {
const auto result = GetExtendedDirectoryStats(wii_path); const auto result = GetExtendedDirectoryStats(wii_path);
if (!result) if (!result)
return result.Error(); return std::unexpected{result.error()};
DirectoryStats stats{}; DirectoryStats stats{};
stats.used_inodes = static_cast<u32>(std::min<u64>(result->used_inodes, TOTAL_INODES)); stats.used_inodes = static_cast<u32>(std::min<u64>(result->used_inodes, TOTAL_INODES));
@@ -810,14 +810,14 @@ Result<ExtendedDirectoryStats>
HostFileSystem::GetExtendedDirectoryStats(const std::string& wii_path) HostFileSystem::GetExtendedDirectoryStats(const std::string& wii_path)
{ {
if (!IsValidPath(wii_path)) if (!IsValidPath(wii_path))
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
ExtendedDirectoryStats stats{}; ExtendedDirectoryStats stats{};
std::string path(BuildFilename(wii_path).host_path); std::string path(BuildFilename(wii_path).host_path);
File::FileInfo info(path); File::FileInfo info(path);
if (!info.Exists()) if (!info.Exists())
{ {
return ResultCode::NotFound; return std::unexpected{ResultCode::NotFound};
} }
if (info.IsDirectory()) if (info.IsDirectory())
{ {
@@ -830,7 +830,7 @@ HostFileSystem::GetExtendedDirectoryStats(const std::string& wii_path)
} }
else else
{ {
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
} }
return stats; return stats;
} }
+15 -14
View File
@@ -4,6 +4,7 @@
#include "Core/IOS/FS/HostBackend/FS.h" #include "Core/IOS/FS/HostBackend/FS.h"
#include <algorithm> #include <algorithm>
#include <expected>
#include <memory> #include <memory>
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
@@ -78,26 +79,26 @@ Result<FileHandle> HostFileSystem::OpenFile(Uid, Gid, const std::string& path, M
{ {
Handle* handle = AssignFreeHandle(); Handle* handle = AssignFreeHandle();
if (!handle) if (!handle)
return ResultCode::NoFreeHandle; return std::unexpected{ResultCode::NoFreeHandle};
const std::string host_path = BuildFilename(path).host_path; const std::string host_path = BuildFilename(path).host_path;
if (File::IsDirectory(host_path)) if (File::IsDirectory(host_path))
{ {
*handle = Handle{}; *handle = Handle{};
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
} }
if (!File::IsFile(host_path)) if (!File::IsFile(host_path))
{ {
*handle = Handle{}; *handle = Handle{};
return ResultCode::NotFound; return std::unexpected{ResultCode::NotFound};
} }
handle->host_file = OpenHostFile(host_path); handle->host_file = OpenHostFile(host_path);
if (!handle->host_file) if (!handle->host_file)
{ {
*handle = Handle{}; *handle = Handle{};
return ResultCode::AccessDenied; return std::unexpected{ResultCode::AccessDenied};
} }
handle->wii_path = path; handle->wii_path = path;
@@ -122,10 +123,10 @@ Result<u32> HostFileSystem::ReadBytesFromFile(Fd fd, u8* ptr, u32 count)
{ {
Handle* handle = GetHandleFromFd(fd); Handle* handle = GetHandleFromFd(fd);
if (!handle || !handle->host_file->IsOpen()) if (!handle || !handle->host_file->IsOpen())
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
if ((u8(handle->mode) & u8(Mode::Read)) == 0) if ((u8(handle->mode) & u8(Mode::Read)) == 0)
return ResultCode::AccessDenied; return std::unexpected{ResultCode::AccessDenied};
const u32 file_size = static_cast<u32>(handle->host_file->GetSize()); const u32 file_size = static_cast<u32>(handle->host_file->GetSize());
// IOS has this check in the read request handler. // IOS has this check in the read request handler.
@@ -137,7 +138,7 @@ Result<u32> HostFileSystem::ReadBytesFromFile(Fd fd, u8* ptr, u32 count)
const u32 actually_read = static_cast<u32>(fread(ptr, 1, count, handle->host_file->GetHandle())); const u32 actually_read = static_cast<u32>(fread(ptr, 1, count, handle->host_file->GetHandle()));
if (actually_read != count && ferror(handle->host_file->GetHandle())) if (actually_read != count && ferror(handle->host_file->GetHandle()))
return ResultCode::AccessDenied; return std::unexpected{ResultCode::AccessDenied};
// IOS returns the number of bytes read and adds that value to the seek position, // IOS returns the number of bytes read and adds that value to the seek position,
// instead of adding the *requested* read length. // instead of adding the *requested* read length.
@@ -149,15 +150,15 @@ Result<u32> HostFileSystem::WriteBytesToFile(Fd fd, const u8* ptr, u32 count)
{ {
Handle* handle = GetHandleFromFd(fd); Handle* handle = GetHandleFromFd(fd);
if (!handle || !handle->host_file->IsOpen()) if (!handle || !handle->host_file->IsOpen())
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
if ((u8(handle->mode) & u8(Mode::Write)) == 0) if ((u8(handle->mode) & u8(Mode::Write)) == 0)
return ResultCode::AccessDenied; return std::unexpected{ResultCode::AccessDenied};
// File might be opened twice, need to seek before we read // File might be opened twice, need to seek before we read
handle->host_file->Seek(handle->file_offset, File::SeekOrigin::Begin); handle->host_file->Seek(handle->file_offset, File::SeekOrigin::Begin);
if (!handle->host_file->WriteBytes(ptr, count)) if (!handle->host_file->WriteBytes(ptr, count))
return ResultCode::AccessDenied; return std::unexpected{ResultCode::AccessDenied};
handle->file_offset += count; handle->file_offset += count;
return count; return count;
@@ -167,7 +168,7 @@ Result<u32> HostFileSystem::SeekFile(Fd fd, std::uint32_t offset, SeekMode mode)
{ {
Handle* handle = GetHandleFromFd(fd); Handle* handle = GetHandleFromFd(fd);
if (!handle || !handle->host_file->IsOpen()) if (!handle || !handle->host_file->IsOpen())
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
u32 new_position = 0; u32 new_position = 0;
switch (mode) switch (mode)
@@ -182,12 +183,12 @@ Result<u32> HostFileSystem::SeekFile(Fd fd, std::uint32_t offset, SeekMode mode)
new_position = handle->host_file->GetSize() + offset; new_position = handle->host_file->GetSize() + offset;
break; break;
default: default:
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
} }
// This differs from POSIX behaviour which allows seeking past the end of the file. // This differs from POSIX behaviour which allows seeking past the end of the file.
if (handle->host_file->GetSize() < new_position) if (handle->host_file->GetSize() < new_position)
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
handle->file_offset = new_position; handle->file_offset = new_position;
return handle->file_offset; return handle->file_offset;
@@ -197,7 +198,7 @@ Result<FileStatus> HostFileSystem::GetFileStatus(Fd fd)
{ {
const Handle* handle = GetHandleFromFd(fd); const Handle* handle = GetHandleFromFd(fd);
if (!handle || !handle->host_file->IsOpen()) if (!handle || !handle->host_file->IsOpen())
return ResultCode::Invalid; return std::unexpected{ResultCode::Invalid};
FileStatus status; FileStatus status;
status.size = handle->host_file->GetSize(); status.size = handle->host_file->GetSize();
+9 -9
View File
@@ -66,29 +66,29 @@ void SysConf::Load()
bool SysConf::LoadFromFile(const IOS::HLE::FS::FileHandle& file) bool SysConf::LoadFromFile(const IOS::HLE::FS::FileHandle& file)
{ {
file.Seek(4, IOS::HLE::FS::SeekMode::Set); (void)file.Seek(4, IOS::HLE::FS::SeekMode::Set);
u16 number_of_entries; u16 number_of_entries;
file.Read(&number_of_entries, 1); (void)file.Read(&number_of_entries, 1);
number_of_entries = Common::swap16(number_of_entries); number_of_entries = Common::swap16(number_of_entries);
std::vector<u16> offsets(number_of_entries); std::vector<u16> offsets(number_of_entries);
for (u16& offset : offsets) for (u16& offset : offsets)
{ {
file.Read(&offset, 1); (void)file.Read(&offset, 1);
offset = Common::swap16(offset); offset = Common::swap16(offset);
} }
for (const u16 offset : offsets) for (const u16 offset : offsets)
{ {
file.Seek(offset, IOS::HLE::FS::SeekMode::Set); (void)file.Seek(offset, IOS::HLE::FS::SeekMode::Set);
// Metadata // Metadata
u8 description = 0; u8 description = 0;
file.Read(&description, 1); (void)file.Read(&description, 1);
const Entry::Type type = static_cast<Entry::Type>((description & 0xe0) >> 5); const Entry::Type type = static_cast<Entry::Type>((description & 0xe0) >> 5);
const u8 name_length = (description & 0x1f) + 1; const u8 name_length = (description & 0x1f) + 1;
std::string name(name_length, '\0'); std::string name(name_length, '\0');
file.Read(&name[0], name.size()); (void)file.Read(name.data(), name.size());
// Data // Data
std::vector<u8> data; std::vector<u8> data;
@@ -97,7 +97,7 @@ bool SysConf::LoadFromFile(const IOS::HLE::FS::FileHandle& file)
case Entry::Type::BigArray: case Entry::Type::BigArray:
{ {
u16 data_length = 0; u16 data_length = 0;
file.Read(&data_length, 1); (void)file.Read(&data_length, 1);
// The stored u16 is length - 1, not length. // The stored u16 is length - 1, not length.
data.resize(Common::swap16(data_length) + 1); data.resize(Common::swap16(data_length) + 1);
break; break;
@@ -105,7 +105,7 @@ bool SysConf::LoadFromFile(const IOS::HLE::FS::FileHandle& file)
case Entry::Type::SmallArray: case Entry::Type::SmallArray:
{ {
u8 data_length = 0; u8 data_length = 0;
file.Read(&data_length, 1); (void)file.Read(&data_length, 1);
data.resize(data_length + 1); data.resize(data_length + 1);
break; break;
} }
@@ -122,7 +122,7 @@ bool SysConf::LoadFromFile(const IOS::HLE::FS::FileHandle& file)
return false; return false;
} }
file.Read(data.data(), data.size()); (void)file.Read(data.data(), data.size());
AddEntry({type, name, std::move(data)}); AddEntry({type, name, std::move(data)});
} }
return true; return true;
+1 -1
View File
@@ -300,7 +300,7 @@ static bool CopySysmenuFilesToFS(FS::FileSystem* fs, const std::string& host_sou
else else
{ {
// Do not overwrite any existing files. // Do not overwrite any existing files.
if (fs->GetMetadata(IOS::SYSMENU_UID, IOS::SYSMENU_UID, nand_path).Succeeded()) if (fs->GetMetadata(IOS::SYSMENU_UID, IOS::SYSMENU_UID, nand_path).has_value())
continue; continue;
File::IOFile host_file{host_path, "rb"}; File::IOFile host_file{host_path, "rb"};
+2 -1
View File
@@ -5,6 +5,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <expected>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -210,7 +211,7 @@ static ConversionResult<OutputParameters> Compress(CompressThreadState* state,
if (retval != Z_OK) if (retval != Z_OK)
{ {
ERROR_LOG_FMT(DISCIO, "Deflate failed"); ERROR_LOG_FMT(DISCIO, "Deflate failed");
return ConversionResultCode::InternalError; return std::unexpected{ConversionResultCode::InternalError};
} }
const int status = deflate(&state->z, Z_FINISH); const int status = deflate(&state->z, Z_FINISH);
+3 -3
View File
@@ -4,6 +4,7 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <expected>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <thread> #include <thread>
@@ -11,7 +12,6 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/Event.h" #include "Common/Event.h"
#include "Common/Result.h"
namespace DiscIO namespace DiscIO
{ {
@@ -25,7 +25,7 @@ enum class ConversionResultCode
}; };
template <typename T> template <typename T>
using ConversionResult = Common::Result<T, ConversionResultCode>; using ConversionResult = std::expected<T, ConversionResultCode>;
// This class starts a number of compression threads and one output thread. // This class starts a number of compression threads and one output thread.
// The set_up_compress_thread_state function is called at the start of each compression thread. // The set_up_compress_thread_state function is called at the start of each compression thread.
@@ -165,7 +165,7 @@ private:
} }
else else
{ {
SetError(result.Error()); SetError(result.error());
} }
state->compress_done_event.Set(); state->compress_done_event.Set();
+6 -5
View File
@@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstring> #include <cstring>
#include <expected>
#include <limits> #include <limits>
#include <map> #include <map>
#include <memory> #include <memory>
@@ -1578,7 +1579,7 @@ WIARVZFileReader<RVZ>::ProcessAndCompress(CompressThreadState* state, CompressPa
if (state->compressor) if (state->compressor)
{ {
if (!state->compressor->Start(entry.exception_lists.size() + entry.main_data.size())) if (!state->compressor->Start(entry.exception_lists.size() + entry.main_data.size()))
return ConversionResultCode::InternalError; return std::unexpected{ConversionResultCode::InternalError};
} }
if (!entry.exception_lists.empty()) if (!entry.exception_lists.empty())
@@ -1588,7 +1589,7 @@ WIARVZFileReader<RVZ>::ProcessAndCompress(CompressThreadState* state, CompressPa
if (!state->compressor->Compress(entry.exception_lists.data(), if (!state->compressor->Compress(entry.exception_lists.data(),
entry.exception_lists.size())) entry.exception_lists.size()))
{ {
return ConversionResultCode::InternalError; return std::unexpected{ConversionResultCode::InternalError};
} }
} }
else else
@@ -1601,7 +1602,7 @@ WIARVZFileReader<RVZ>::ProcessAndCompress(CompressThreadState* state, CompressPa
if (!state->compressor->AddPrecedingDataOnlyForPurgeHashing(entry.exception_lists.data(), if (!state->compressor->AddPrecedingDataOnlyForPurgeHashing(entry.exception_lists.data(),
entry.exception_lists.size())) entry.exception_lists.size()))
{ {
return ConversionResultCode::InternalError; return std::unexpected{ConversionResultCode::InternalError};
} }
} }
} }
@@ -1610,9 +1611,9 @@ WIARVZFileReader<RVZ>::ProcessAndCompress(CompressThreadState* state, CompressPa
if (state->compressor) if (state->compressor)
{ {
if (!state->compressor->Compress(entry.main_data.data(), entry.main_data.size())) if (!state->compressor->Compress(entry.main_data.data(), entry.main_data.size()))
return ConversionResultCode::InternalError; return std::unexpected{ConversionResultCode::InternalError};
if (!state->compressor->End()) if (!state->compressor->End())
return ConversionResultCode::InternalError; return std::unexpected{ConversionResultCode::InternalError};
} }
bool compressed = !!state->compressor; bool compressed = !!state->compressor;
-1
View File
@@ -154,7 +154,6 @@
<ClInclude Include="Common\Projection.h" /> <ClInclude Include="Common\Projection.h" />
<ClInclude Include="Common\QoSSession.h" /> <ClInclude Include="Common\QoSSession.h" />
<ClInclude Include="Common\Random.h" /> <ClInclude Include="Common\Random.h" />
<ClInclude Include="Common\Result.h" />
<ClInclude Include="Common\scmrev.h" /> <ClInclude Include="Common\scmrev.h" />
<ClInclude Include="Common\ScopeGuard.h" /> <ClInclude Include="Common\ScopeGuard.h" />
<ClInclude Include="Common\SDCardUtil.h" /> <ClInclude Include="Common\SDCardUtil.h" />
+1 -1
View File
@@ -553,7 +553,7 @@ void CheatSearchWidget::GenerateARCodes()
} }
else else
{ {
const auto new_error_code = result.Error(); const auto new_error_code = result.error();
if (!error_code.has_value()) if (!error_code.has_value())
{ {
error_code = new_error_code; error_code = new_error_code;
+51 -51
View File
@@ -96,7 +96,7 @@ TEST_F(FileSystemTest, EssentialDirectories)
for (const std::string path : for (const std::string path :
{"/sys", "/ticket", "/title", "/shared1", "/shared2", "/tmp", "/import", "/meta"}) {"/sys", "/ticket", "/title", "/shared1", "/shared2", "/tmp", "/import", "/meta"})
{ {
EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, path).Succeeded()) << path; EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, path).has_value()) << path;
} }
} }
@@ -109,7 +109,7 @@ TEST_F(FileSystemTest, CreateFile)
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, ArbitraryAttribute, modes), ResultCode::Success); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, ArbitraryAttribute, modes), ResultCode::Success);
const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH); const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH);
ASSERT_TRUE(stats.Succeeded()); ASSERT_TRUE(stats.has_value());
EXPECT_TRUE(stats->is_file); EXPECT_TRUE(stats->is_file);
EXPECT_EQ(stats->size, 0u); EXPECT_EQ(stats->size, 0u);
EXPECT_EQ(stats->uid, 0u); EXPECT_EQ(stats->uid, 0u);
@@ -120,7 +120,7 @@ TEST_F(FileSystemTest, CreateFile)
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, 0, modes), ResultCode::AlreadyExists); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, 0, modes), ResultCode::AlreadyExists);
const Result<std::vector<std::string>> tmp_files = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp"); const Result<std::vector<std::string>> tmp_files = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp");
ASSERT_TRUE(tmp_files.Succeeded()); ASSERT_TRUE(tmp_files.has_value());
EXPECT_EQ(std::ranges::count(*tmp_files, "f"), 1u); EXPECT_EQ(std::ranges::count(*tmp_files, "f"), 1u);
// Test invalid paths // Test invalid paths
@@ -141,7 +141,7 @@ TEST_F(FileSystemTest, CreateDirectory)
ResultCode::Success); ResultCode::Success);
const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH); const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH);
ASSERT_TRUE(stats.Succeeded()); ASSERT_TRUE(stats.has_value());
EXPECT_FALSE(stats->is_file); EXPECT_FALSE(stats->is_file);
EXPECT_EQ(stats->uid, 0u); EXPECT_EQ(stats->uid, 0u);
EXPECT_EQ(stats->gid, 0); EXPECT_EQ(stats->gid, 0);
@@ -149,7 +149,7 @@ TEST_F(FileSystemTest, CreateDirectory)
EXPECT_EQ(stats->attribute, ArbitraryAttribute); EXPECT_EQ(stats->attribute, ArbitraryAttribute);
const Result<std::vector<std::string>> children = m_fs->ReadDirectory(Uid{0}, Gid{0}, PATH); const Result<std::vector<std::string>> children = m_fs->ReadDirectory(Uid{0}, Gid{0}, PATH);
ASSERT_TRUE(children.Succeeded()); ASSERT_TRUE(children.has_value());
EXPECT_TRUE(children->empty()); EXPECT_TRUE(children->empty());
EXPECT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, PATH, 0, modes), ResultCode::AlreadyExists); EXPECT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, PATH, 0, modes), ResultCode::AlreadyExists);
@@ -161,9 +161,9 @@ TEST_F(FileSystemTest, CreateDirectory)
TEST_F(FileSystemTest, Delete) TEST_F(FileSystemTest, Delete)
{ {
EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").Succeeded()); EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").has_value());
EXPECT_EQ(m_fs->Delete(Uid{0}, Gid{0}, "/tmp"), ResultCode::Success); EXPECT_EQ(m_fs->Delete(Uid{0}, Gid{0}, "/tmp"), ResultCode::Success);
EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").Error(), ResultCode::NotFound); EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").error(), ResultCode::NotFound);
// Test recursive directory deletion. // Test recursive directory deletion.
ASSERT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, "/sys/1", 0, modes), ResultCode::Success); ASSERT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, "/sys/1", 0, modes), ResultCode::Success);
@@ -173,7 +173,7 @@ TEST_F(FileSystemTest, Delete)
// Leave a file open. Deletion should fail while the file is in use. // Leave a file open. Deletion should fail while the file is in use.
auto handle = std::make_optional(m_fs->OpenFile(Uid{0}, Gid{0}, "/sys/1/2/3", Mode::Read)); auto handle = std::make_optional(m_fs->OpenFile(Uid{0}, Gid{0}, "/sys/1/2/3", Mode::Read));
ASSERT_TRUE(handle->Succeeded()); ASSERT_TRUE(handle->has_value());
EXPECT_EQ(m_fs->Delete(Uid{0}, Gid{0}, "/sys/1/2/3"), ResultCode::InUse); EXPECT_EQ(m_fs->Delete(Uid{0}, Gid{0}, "/sys/1/2/3"), ResultCode::InUse);
// A directory that contains a file that is in use is considered to be in use, // A directory that contains a file that is in use is considered to be in use,
// so this should fail too. // so this should fail too.
@@ -187,12 +187,12 @@ TEST_F(FileSystemTest, Delete)
TEST_F(FileSystemTest, Rename) TEST_F(FileSystemTest, Rename)
{ {
EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").Succeeded()); EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").has_value());
EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp", "/test"), ResultCode::Success); EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp", "/test"), ResultCode::Success);
EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").Error(), ResultCode::NotFound); EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp").error(), ResultCode::NotFound);
EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/test").Succeeded()); EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/test").has_value());
// Rename /test back to /tmp. // Rename /test back to /tmp.
EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/test", "/tmp"), ResultCode::Success); EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/test", "/tmp"), ResultCode::Success);
@@ -213,9 +213,9 @@ TEST_F(FileSystemTest, RenameWithExistingTargetDirectory)
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/d2/file", 0, modes), ResultCode::Success); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/d2/file", 0, modes), ResultCode::Success);
EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp/d", "/tmp/d2"), ResultCode::Success); EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp/d", "/tmp/d2"), ResultCode::Success);
EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/d").Error(), ResultCode::NotFound); EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/d").error(), ResultCode::NotFound);
const Result<std::vector<std::string>> children = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/d2"); const Result<std::vector<std::string>> children = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/d2");
ASSERT_TRUE(children.Succeeded()); ASSERT_TRUE(children.has_value());
EXPECT_TRUE(children->empty()); EXPECT_TRUE(children->empty());
} }
@@ -230,8 +230,8 @@ TEST_F(FileSystemTest, RenameWithExistingTargetFile)
std::vector<u8> read_buffer(TEST_DATA.size()); std::vector<u8> read_buffer(TEST_DATA.size());
{ {
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, source_path, Mode::ReadWrite); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, source_path, Mode::ReadWrite);
ASSERT_TRUE(file.Succeeded()); ASSERT_TRUE(file.has_value());
ASSERT_TRUE(file->Write(TEST_DATA.data(), TEST_DATA.size()).Succeeded()); ASSERT_TRUE(file->Write(TEST_DATA.data(), TEST_DATA.size()).has_value());
} }
// Create the test target file and leave it empty. // Create the test target file and leave it empty.
@@ -240,11 +240,11 @@ TEST_F(FileSystemTest, RenameWithExistingTargetFile)
// Rename /sys/f2 to /tmp/f2 and check that f1 replaced f2. // Rename /sys/f2 to /tmp/f2 and check that f1 replaced f2.
EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, source_path, dest_path), ResultCode::Success); EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, source_path, dest_path), ResultCode::Success);
ASSERT_FALSE(m_fs->GetMetadata(Uid{0}, Gid{0}, source_path).Succeeded()); ASSERT_FALSE(m_fs->GetMetadata(Uid{0}, Gid{0}, source_path).has_value());
EXPECT_EQ(m_fs->GetMetadata(Uid{0}, Gid{0}, source_path).Error(), ResultCode::NotFound); EXPECT_EQ(m_fs->GetMetadata(Uid{0}, Gid{0}, source_path).error(), ResultCode::NotFound);
const Result<Metadata> metadata = m_fs->GetMetadata(Uid{0}, Gid{0}, dest_path); const Result<Metadata> metadata = m_fs->GetMetadata(Uid{0}, Gid{0}, dest_path);
ASSERT_TRUE(metadata.Succeeded()); ASSERT_TRUE(metadata.has_value());
EXPECT_TRUE(metadata->is_file); EXPECT_TRUE(metadata->is_file);
EXPECT_EQ(metadata->size, TEST_DATA.size()); EXPECT_EQ(metadata->size, TEST_DATA.size());
} }
@@ -253,7 +253,7 @@ TEST_F(FileSystemTest, GetDirectoryStats)
{ {
auto check_stats = [this](const u32 clusters, const u32 inodes) { auto check_stats = [this](const u32 clusters, const u32 inodes) {
const Result<DirectoryStats> stats = m_fs->GetDirectoryStats("/tmp"); const Result<DirectoryStats> stats = m_fs->GetDirectoryStats("/tmp");
ASSERT_TRUE(stats.Succeeded()); ASSERT_TRUE(stats.has_value());
EXPECT_EQ(stats->used_clusters, clusters); EXPECT_EQ(stats->used_clusters, clusters);
EXPECT_EQ(stats->used_inodes, inodes); EXPECT_EQ(stats->used_inodes, inodes);
}; };
@@ -266,7 +266,7 @@ TEST_F(FileSystemTest, GetDirectoryStats)
{ {
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/file", Mode::Write); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/file", Mode::Write);
file->Write(std::vector<u8>(20).data(), 20); (void)file->Write(std::vector<u8>(20).data(), 20);
} }
// The file should now take up one cluster. // The file should now take up one cluster.
check_stats(1u, 2u); check_stats(1u, 2u);
@@ -277,16 +277,16 @@ TEST_F(FileSystemTest, GetDirectoryStats)
TEST_F(FileSystemTest, NonExistingFiles) TEST_F(FileSystemTest, NonExistingFiles)
{ {
const Result<Metadata> metadata = m_fs->GetMetadata(Uid{0}, Gid{0}, "/tmp/foo"); const Result<Metadata> metadata = m_fs->GetMetadata(Uid{0}, Gid{0}, "/tmp/foo");
ASSERT_FALSE(metadata.Succeeded()); ASSERT_FALSE(metadata.has_value());
EXPECT_EQ(metadata.Error(), ResultCode::NotFound); EXPECT_EQ(metadata.error(), ResultCode::NotFound);
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/foo", Mode::Read); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/foo", Mode::Read);
ASSERT_FALSE(file.Succeeded()); ASSERT_FALSE(file.has_value());
EXPECT_EQ(file.Error(), ResultCode::NotFound); EXPECT_EQ(file.error(), ResultCode::NotFound);
const Result<std::vector<std::string>> children = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/foo"); const Result<std::vector<std::string>> children = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/foo");
ASSERT_FALSE(children.Succeeded()); ASSERT_FALSE(children.has_value());
EXPECT_EQ(children.Error(), ResultCode::NotFound); EXPECT_EQ(children.error(), ResultCode::NotFound);
} }
TEST_F(FileSystemTest, Seek) TEST_F(FileSystemTest, Seek)
@@ -296,7 +296,7 @@ TEST_F(FileSystemTest, Seek)
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(file.Succeeded()); ASSERT_TRUE(file.has_value());
// An empty file should have a size of exactly 0 bytes. // An empty file should have a size of exactly 0 bytes.
EXPECT_EQ(file->GetStatus()->size, 0u); EXPECT_EQ(file->GetStatus()->size, 0u);
@@ -304,14 +304,14 @@ TEST_F(FileSystemTest, Seek)
EXPECT_EQ(file->GetStatus()->offset, 0u); EXPECT_EQ(file->GetStatus()->offset, 0u);
// Write some dummy data. // Write some dummy data.
ASSERT_TRUE(file->Write(TEST_DATA.data(), TEST_DATA.size()).Succeeded()); ASSERT_TRUE(file->Write(TEST_DATA.data(), TEST_DATA.size()).has_value());
EXPECT_EQ(file->GetStatus()->size, TEST_DATA.size()); EXPECT_EQ(file->GetStatus()->size, TEST_DATA.size());
EXPECT_EQ(file->GetStatus()->offset, TEST_DATA.size()); EXPECT_EQ(file->GetStatus()->offset, TEST_DATA.size());
auto seek_and_check = [&file](const u32 offset, const SeekMode mode, auto seek_and_check = [&file](const u32 offset, const SeekMode mode,
const u32 expected_position) { const u32 expected_position) {
const Result<u32> new_offset = file->Seek(offset, mode); const Result<u32> new_offset = file->Seek(offset, mode);
ASSERT_TRUE(new_offset.Succeeded()); ASSERT_TRUE(new_offset.has_value());
EXPECT_EQ(*new_offset, expected_position); EXPECT_EQ(*new_offset, expected_position);
EXPECT_EQ(file->GetStatus()->offset, expected_position); EXPECT_EQ(file->GetStatus()->offset, expected_position);
}; };
@@ -324,8 +324,8 @@ TEST_F(FileSystemTest, Seek)
// Test past-EOF seeks. // Test past-EOF seeks.
const Result<u32> new_position = file->Seek(11, SeekMode::Set); const Result<u32> new_position = file->Seek(11, SeekMode::Set);
ASSERT_FALSE(new_position.Succeeded()); ASSERT_FALSE(new_position.has_value());
EXPECT_EQ(new_position.Error(), ResultCode::Invalid); EXPECT_EQ(new_position.error(), ResultCode::Invalid);
} }
TEST_F(FileSystemTest, WriteAndSimpleReadback) TEST_F(FileSystemTest, WriteAndSimpleReadback)
@@ -336,14 +336,14 @@ TEST_F(FileSystemTest, WriteAndSimpleReadback)
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(file.Succeeded()); ASSERT_TRUE(file.has_value());
// Write some test data. // Write some test data.
ASSERT_TRUE(file->Write(TEST_DATA.data(), TEST_DATA.size()).Succeeded()); ASSERT_TRUE(file->Write(TEST_DATA.data(), TEST_DATA.size()).has_value());
// Now read it back and make sure it is identical. // Now read it back and make sure it is identical.
ASSERT_TRUE(file->Seek(0, SeekMode::Set).Succeeded()); ASSERT_TRUE(file->Seek(0, SeekMode::Set).has_value());
ASSERT_TRUE(file->Read(read_buffer.data(), read_buffer.size()).Succeeded()); ASSERT_TRUE(file->Read(read_buffer.data(), read_buffer.size()).has_value());
EXPECT_EQ(TEST_DATA, read_buffer); EXPECT_EQ(TEST_DATA, read_buffer);
} }
@@ -356,31 +356,31 @@ TEST_F(FileSystemTest, WriteAndRead)
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
Result<FileHandle> tmp_handle = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); Result<FileHandle> tmp_handle = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(tmp_handle.Succeeded()); ASSERT_TRUE(tmp_handle.has_value());
const Fd fd = tmp_handle->Release(); const Fd fd = tmp_handle->Release();
// Try to read from an empty file. This should do nothing. // Try to read from an empty file. This should do nothing.
// See https://github.com/dolphin-emu/dolphin/pull/4942 // See https://github.com/dolphin-emu/dolphin/pull/4942
Result<u32> read_result = m_fs->ReadBytesFromFile(fd, buffer.data(), TEST_DATA_SIZE); Result<u32> read_result = m_fs->ReadBytesFromFile(fd, buffer.data(), TEST_DATA_SIZE);
EXPECT_TRUE(read_result.Succeeded()); EXPECT_TRUE(read_result.has_value());
EXPECT_EQ(*read_result, 0u); EXPECT_EQ(*read_result, 0u);
EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, 0u); EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, 0u);
ASSERT_TRUE(m_fs->WriteBytesToFile(fd, TEST_DATA.data(), TEST_DATA_SIZE).Succeeded()); ASSERT_TRUE(m_fs->WriteBytesToFile(fd, TEST_DATA.data(), TEST_DATA_SIZE).has_value());
EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, TEST_DATA.size()); EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, TEST_DATA.size());
// Try to read past EOF while we are at the end of the file. This should do nothing too. // Try to read past EOF while we are at the end of the file. This should do nothing too.
read_result = m_fs->ReadBytesFromFile(fd, buffer.data(), TEST_DATA_SIZE); read_result = m_fs->ReadBytesFromFile(fd, buffer.data(), TEST_DATA_SIZE);
EXPECT_TRUE(read_result.Succeeded()); EXPECT_TRUE(read_result.has_value());
EXPECT_EQ(*read_result, 0u); EXPECT_EQ(*read_result, 0u);
EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, TEST_DATA.size()); EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, TEST_DATA.size());
// Go back to the start and try to read past EOF. This should read the entire file until EOF. // Go back to the start and try to read past EOF. This should read the entire file until EOF.
ASSERT_TRUE(m_fs->SeekFile(fd, 0, SeekMode::Set).Succeeded()); ASSERT_TRUE(m_fs->SeekFile(fd, 0, SeekMode::Set).has_value());
const u32 LARGER_TEST_DATA_SIZE = TEST_DATA_SIZE + 10; const u32 LARGER_TEST_DATA_SIZE = TEST_DATA_SIZE + 10;
std::vector<u8> larger_buffer(LARGER_TEST_DATA_SIZE); std::vector<u8> larger_buffer(LARGER_TEST_DATA_SIZE);
read_result = m_fs->ReadBytesFromFile(fd, larger_buffer.data(), LARGER_TEST_DATA_SIZE); read_result = m_fs->ReadBytesFromFile(fd, larger_buffer.data(), LARGER_TEST_DATA_SIZE);
EXPECT_TRUE(read_result.Succeeded()); EXPECT_TRUE(read_result.has_value());
EXPECT_EQ(*read_result, TEST_DATA.size()); EXPECT_EQ(*read_result, TEST_DATA.size());
EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, TEST_DATA.size()); EXPECT_EQ(m_fs->GetFileStatus(fd)->offset, TEST_DATA.size());
} }
@@ -391,15 +391,15 @@ TEST_F(FileSystemTest, MultipleHandles)
{ {
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(file.Succeeded()); ASSERT_TRUE(file.has_value());
// Fill it with 10 zeroes. // Fill it with 10 zeroes.
ASSERT_TRUE(file->Write(std::vector<u8>(10).data(), 10).Succeeded()); ASSERT_TRUE(file->Write(std::vector<u8>(10).data(), 10).has_value());
} }
const Result<FileHandle> file1 = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file1 = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
const Result<FileHandle> file2 = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file2 = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(file1.Succeeded()); ASSERT_TRUE(file1.has_value());
ASSERT_TRUE(file2.Succeeded()); ASSERT_TRUE(file2.has_value());
// Write some test data using one handle and make sure the data is seen by the other handle // Write some test data using one handle and make sure the data is seen by the other handle
// (see issue 2917, 5232 and 8702 and https://github.com/dolphin-emu/dolphin/pull/2649). // (see issue 2917, 5232 and 8702 and https://github.com/dolphin-emu/dolphin/pull/2649).
@@ -407,12 +407,12 @@ TEST_F(FileSystemTest, MultipleHandles)
const std::vector<u8> TEST_DATA{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; const std::vector<u8> TEST_DATA{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
EXPECT_EQ(file1->GetStatus()->offset, 0u); EXPECT_EQ(file1->GetStatus()->offset, 0u);
ASSERT_TRUE(file1->Write(TEST_DATA.data(), TEST_DATA.size()).Succeeded()); ASSERT_TRUE(file1->Write(TEST_DATA.data(), TEST_DATA.size()).has_value());
EXPECT_EQ(file1->GetStatus()->offset, 10u); EXPECT_EQ(file1->GetStatus()->offset, 10u);
std::vector<u8> read_buffer(TEST_DATA.size()); std::vector<u8> read_buffer(TEST_DATA.size());
EXPECT_EQ(file2->GetStatus()->offset, 0u); EXPECT_EQ(file2->GetStatus()->offset, 0u);
ASSERT_TRUE(file2->Read(read_buffer.data(), read_buffer.size()).Succeeded()); ASSERT_TRUE(file2->Read(read_buffer.data(), read_buffer.size()).has_value());
EXPECT_EQ(file2->GetStatus()->offset, 10u); EXPECT_EQ(file2->GetStatus()->offset, 10u);
EXPECT_EQ(TEST_DATA, read_buffer); EXPECT_EQ(TEST_DATA, read_buffer);
} }
@@ -424,8 +424,8 @@ TEST_F(FileSystemTest, ReadDirectoryOnFile)
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
const Result<std::vector<std::string>> result = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/f"); const Result<std::vector<std::string>> result = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/f");
ASSERT_FALSE(result.Succeeded()); ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.Error(), ResultCode::Invalid); EXPECT_EQ(result.error(), ResultCode::Invalid);
} }
TEST_F(FileSystemTest, ReadDirectoryOrdering) TEST_F(FileSystemTest, ReadDirectoryOrdering)
@@ -447,7 +447,7 @@ TEST_F(FileSystemTest, ReadDirectoryOrdering)
// Verify that ReadDirectory returns a file list that is ordered by descending creation date // Verify that ReadDirectory returns a file list that is ordered by descending creation date
// (issue 10234). // (issue 10234).
const Result<std::vector<std::string>> result = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/o"); const Result<std::vector<std::string>> result = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/o");
ASSERT_TRUE(result.Succeeded()); ASSERT_TRUE(result.has_value());
ASSERT_EQ(result->size(), file_names.size()); ASSERT_EQ(result->size(), file_names.size());
EXPECT_TRUE(std::equal(result->begin(), result->end(), file_names.rbegin())); EXPECT_TRUE(std::equal(result->begin(), result->end(), file_names.rbegin()));
} }
@@ -458,7 +458,7 @@ TEST_F(FileSystemTest, CreateFullPath)
// Parent directories should be created by CreateFullPath. // Parent directories should be created by CreateFullPath.
for (const std::string path : {"/tmp", "/tmp/a", "/tmp/a/b", "/tmp/a/b/c"}) for (const std::string path : {"/tmp", "/tmp/a", "/tmp/a/b", "/tmp/a/b/c"})
EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, path).Succeeded()); EXPECT_TRUE(m_fs->ReadDirectory(Uid{0}, Gid{0}, path).has_value());
// If parent directories already exist, the call should still succeed. // If parent directories already exist, the call should still succeed.
EXPECT_EQ(m_fs->CreateFullPath(Uid{0}, Gid{0}, "/tmp/a/b/c/d", 0, modes), ResultCode::Success); EXPECT_EQ(m_fs->CreateFullPath(Uid{0}, Gid{0}, "/tmp/a/b/c/d", 0, modes), ResultCode::Success);