diff --git a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp index f6998621da..64b6112d19 100644 --- a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp +++ b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp @@ -616,8 +616,8 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index, } } - NWC24::ErrorCode reply = IOS::HLE::NWC24::OpenVFF(m_dl_list.GetVFFPath(entry_index), content_name, - m_ios.GetFS(), file_data); + NWC24::ErrorCode reply = IOS::HLE::NWC24::WriteToVFF(m_dl_list.GetVFFPath(entry_index), + content_name, m_ios.GetFS(), file_data); if (reply != NWC24::WC24_OK) { diff --git a/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp b/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp index c616199105..01d041644d 100644 --- a/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp +++ b/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp @@ -237,6 +237,48 @@ static ErrorCode WriteFile(const std::string& filename, const std::vector& t return WC24_OK; } +static ErrorCode ReadFile(const std::string& filename, std::vector& out) +{ + FIL src{}; + const auto open_error_code = f_open(&src, filename.c_str(), FA_READ); + if (open_error_code != FR_OK) + { + ERROR_LOG_FMT(IOS_WC24, "Failed to open file {} in VFF", filename); + return WC24_ERR_FILE_OPEN; + } + + Common::ScopeGuard vff_close_guard{[&] { f_close(&src); }}; + + u32 size = static_cast(out.size()); + u32 read_size{}; + const auto read_error_code = f_read(&src, out.data(), size, &read_size); + if (read_error_code != FR_OK) + { + ERROR_LOG_FMT(IOS_WC24, "Failed to read file {} in VFF: {}", filename, + static_cast(read_error_code)); + return WC24_ERR_FILE_READ; + } + + if (read_size != size) + { + ERROR_LOG_FMT(IOS_WC24, "Failed to read bytes of file {} to VFF ({} != {})", filename, + read_size, size); + return WC24_ERR_FILE_READ; + } + + // As prior operations did not fail, dismiss the guard and handle a potential error with f_close. + vff_close_guard.Dismiss(); + + const auto close_error_code = f_close(&src); + if (close_error_code != FR_OK) + { + ERROR_LOG_FMT(IOS_WC24, "Failed to close file {} in VFF", filename); + return WC24_ERR_FILE_CLOSE; + } + + return WC24_OK; +} + namespace { class VffFatFsCallbacks : public Common::FatFsCallbacks @@ -258,8 +300,8 @@ public: }; } // namespace -ErrorCode OpenVFF(const std::string& path, const std::string& filename, - const std::shared_ptr& fs, const std::vector& data) +ErrorCode WriteToVFF(const std::string& path, const std::string& filename, + const std::shared_ptr& fs, const std::vector& data) { VffFatFsCallbacks callbacks; ErrorCode return_value; @@ -286,6 +328,8 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename, return; } + Common::ScopeGuard unmount_guard{[] { f_unmount(""); }}; + const FRESULT vff_mount_error_code = vff_mount(callbacks.m_vff, &fatfs); if (vff_mount_error_code != FR_OK) { @@ -295,8 +339,6 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename, return; } - Common::ScopeGuard unmount_guard{[] { f_unmount(""); }}; - const auto write_error_code = WriteFile(filename, data); if (write_error_code != WC24_OK) { @@ -312,4 +354,108 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename, return return_value; } + +ErrorCode ReadFromVFF(const std::string& path, const std::string& filename, + const std::shared_ptr& fs, std::vector& out) +{ + VffFatFsCallbacks callbacks; + ErrorCode return_value; + Common::RunInFatFsContext(callbacks, [&]() { + auto temp = fs->OpenFile(PID_KD, PID_KD, path, FS::Mode::ReadWrite); + if (!temp) + { + ERROR_LOG_FMT(IOS_WC24, "Failed to open VFF at: {}", path); + return_value = WC24_ERR_NOT_FOUND; + return; + } + + callbacks.m_vff = &*temp; + + FATFS fatfs{}; + const FRESULT fatfs_mount_error_code = f_mount(&fatfs, "", 0); + if (fatfs_mount_error_code != FR_OK) + { + // The VFF is most likely broken. + ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path); + return_value = WC24_ERR_BROKEN; + return; + } + + Common::ScopeGuard unmount_guard{[] { f_unmount(""); }}; + + const FRESULT vff_mount_error_code = vff_mount(callbacks.m_vff, &fatfs); + if (vff_mount_error_code != FR_OK) + { + // The VFF is most likely broken. + ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path); + return_value = WC24_ERR_BROKEN; + return; + } + + const ErrorCode read_error_code = ReadFile(filename, out); + if (read_error_code != WC24_OK) + { + return_value = read_error_code; + return; + } + + return_value = WC24_OK; + return; + }); + + return return_value; +} + +ErrorCode DeleteFileFromVFF(const std::string& path, const std::string& filename, + const std::shared_ptr& fs) +{ + VffFatFsCallbacks callbacks; + ErrorCode return_value; + Common::RunInFatFsContext(callbacks, [&]() { + auto temp = fs->OpenFile(PID_KD, PID_KD, path, FS::Mode::ReadWrite); + if (!temp) + { + ERROR_LOG_FMT(IOS_WC24, "Failed to open VFF at: {}", path); + return_value = WC24_ERR_NOT_FOUND; + return; + } + + callbacks.m_vff = &*temp; + + FATFS fatfs{}; + const FRESULT fatfs_mount_error_code = f_mount(&fatfs, "", 0); + if (fatfs_mount_error_code != FR_OK) + { + // The VFF is most likely broken. + ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path); + return_value = WC24_ERR_BROKEN; + return; + } + + Common::ScopeGuard unmount_guard{[] { f_unmount(""); }}; + + const FRESULT vff_mount_error_code = vff_mount(callbacks.m_vff, &fatfs); + if (vff_mount_error_code != FR_OK) + { + // The VFF is most likely broken. + ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path); + return_value = WC24_ERR_BROKEN; + return; + } + + const FRESULT unlink_code = f_unlink(filename.c_str()); + if (unlink_code != FR_OK) + { + ERROR_LOG_FMT(IOS_WC24, "Failed to delete file {} in VFF at: {} Code: {}", filename, path, + static_cast(unlink_code)); + return_value = WC24_ERR_BROKEN; + return; + } + + return_value = WC24_OK; + return; + }); + + return return_value; +} } // namespace IOS::HLE::NWC24 diff --git a/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.h b/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.h index ca3dc4c5a8..5decfb90e4 100644 --- a/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.h +++ b/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.h @@ -22,8 +22,12 @@ namespace NWC24 constexpr u16 SECTOR_SIZE = 512; constexpr u16 VF_LITTLE_ENDIAN = 0xFFFE; constexpr u16 VF_BIG_ENDIAN = 0xFEFF; -ErrorCode OpenVFF(const std::string& path, const std::string& filename, - const std::shared_ptr& fs, const std::vector& data); +ErrorCode WriteToVFF(const std::string& path, const std::string& filename, + const std::shared_ptr& fs, const std::vector& data); +ErrorCode ReadFromVFF(const std::string& path, const std::string& filename, + const std::shared_ptr& fs, std::vector& out); +ErrorCode DeleteFileFromVFF(const std::string& path, const std::string& filename, + const std::shared_ptr& fs); #pragma pack(push, 1) struct VFFHeader final