mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 03:55:32 +00:00
initial cellGameThemeInstall and cellGameThemeInstallFromBuffer
This commit is contained in:
parent
4d09be25aa
commit
8e667e69f6
9 changed files with 160 additions and 31 deletions
|
@ -5,6 +5,7 @@
|
|||
#include "utils.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "sha256.h"
|
||||
#include "key_vault.h"
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
@ -138,6 +139,27 @@ char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PA
|
|||
return real_file_name;
|
||||
}
|
||||
|
||||
std::string sha256_get_hash(const char* data, usz size, bool lower_case)
|
||||
{
|
||||
u8 res_hash[32];
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts_ret(&ctx, 0);
|
||||
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(data), size);
|
||||
mbedtls_sha256_finish_ret(&ctx, res_hash);
|
||||
|
||||
std::string res_hash_string("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
||||
for (usz index = 0; index < 32; index++)
|
||||
{
|
||||
const auto pal = lower_case ? "0123456789abcdef" : "0123456789ABCDEF";
|
||||
res_hash_string[index * 2] = pal[res_hash[index] >> 4];
|
||||
res_hash_string[(index * 2) + 1] = pal[res_hash[index] & 15];
|
||||
}
|
||||
|
||||
return res_hash_string;
|
||||
}
|
||||
|
||||
void mbedtls_zeroize(void *v, size_t n)
|
||||
{
|
||||
static void *(*const volatile unop_memset)(void *, int, size_t) = &memset;
|
||||
|
|
|
@ -40,6 +40,8 @@ inline u64 swap64(u64 i)
|
|||
|
||||
char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH]);
|
||||
|
||||
std::string sha256_get_hash(const char* data, usz size, bool lower_case);
|
||||
|
||||
// Hex string conversion auxiliary functions.
|
||||
u64 hex_to_u64(const char* hex_str);
|
||||
void hex_to_bytes(unsigned char *data, const char *hex_str, unsigned int str_length);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Utilities/StrUtil.h"
|
||||
#include "util/init_mutex.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include "Crypto/utils.h"
|
||||
|
||||
#include <span>
|
||||
|
||||
|
@ -1394,18 +1395,144 @@ error_code cellGameThemeInstall(vm::cptr<char> usrdirPath, vm::cptr<char> fileNa
|
|||
return CELL_GAME_ERROR_PARAM;
|
||||
}
|
||||
|
||||
const std::string src_path = vfs::get(fmt::format("%s/%s", usrdirPath, fileName));
|
||||
|
||||
// Use hash to get a hopefully unique filename
|
||||
std::string hash;
|
||||
|
||||
if (fs::file theme = fs::file(src_path))
|
||||
{
|
||||
u32 magic{};
|
||||
|
||||
if (src_path.ends_with(".p3t") || !theme.read(magic) || magic != "P3TF"_u32)
|
||||
{
|
||||
return CELL_GAME_ERROR_INVALID_THEME_FILE;
|
||||
}
|
||||
|
||||
hash = sha256_get_hash(theme.to_string().c_str(), theme.size(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_GAME_ERROR_NOTFOUND;
|
||||
}
|
||||
|
||||
const std::string dst_path = vfs::get(fmt::format("/dev_hdd0/theme/%s_%s.p3t", Emu.GetTitleID(), hash)); // TODO: this is renamed with some other scheme
|
||||
|
||||
if (fs::is_file(dst_path))
|
||||
{
|
||||
cellGame.notice("cellGameThemeInstall: theme already installed: '%s'", dst_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
cellGame.notice("cellGameThemeInstall: copying theme from '%s' to '%s'", src_path, dst_path);
|
||||
|
||||
if (!fs::copy_file(src_path, dst_path, false)) // TODO: new file is write protected
|
||||
{
|
||||
cellGame.error("cellGameThemeInstall: failed to copy theme from '%s' to '%s' (error=%s)", src_path, dst_path, fs::g_tls_error);
|
||||
return CELL_GAME_ERROR_ACCESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (false && !fs::remove_file(src_path)) // TODO: disabled for now
|
||||
{
|
||||
cellGame.error("cellGameThemeInstall: failed to remove source theme from '%s' (error=%s)", src_path, fs::g_tls_error);
|
||||
}
|
||||
|
||||
if (option == CELL_GAME_THEME_OPTION_APPLY)
|
||||
{
|
||||
// TODO: apply new theme
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellGameThemeInstallFromBuffer(u32 fileSize, u32 bufSize, vm::ptr<void> buf, vm::ptr<CellGameThemeInstallCallback> func, u32 option)
|
||||
error_code cellGameThemeInstallFromBuffer(ppu_thread& ppu, u32 fileSize, u32 bufSize, vm::ptr<void> buf, vm::ptr<CellGameThemeInstallCallback> func, u32 option)
|
||||
{
|
||||
cellGame.todo("cellGameThemeInstallFromBuffer(fileSize=%d, bufSize=%d, buf=*0x%x, func=*0x%x, option=0x%x)", fileSize, bufSize, buf, func, option);
|
||||
|
||||
if (!buf || !fileSize || (fileSize > bufSize && !func) || bufSize <= 4095 || option > CELL_GAME_THEME_OPTION_APPLY)
|
||||
if (!buf || !fileSize || (fileSize > bufSize && !func) || bufSize < CELL_GAME_THEMEINSTALL_BUFSIZE_MIN || option > CELL_GAME_THEME_OPTION_APPLY)
|
||||
{
|
||||
return CELL_GAME_ERROR_PARAM;
|
||||
}
|
||||
|
||||
const std::string hash = sha256_get_hash(reinterpret_cast<char*>(buf.get_ptr()), fileSize, true);
|
||||
const std::string dst_path = vfs::get(fmt::format("/dev_hdd0/theme/%s_%s.p3t", Emu.GetTitleID(), hash)); // TODO: this is renamed with some scheme
|
||||
|
||||
if (fs::file theme = fs::file(dst_path, fs::write_new + fs::isfile)) // TODO: new file is write protected
|
||||
{
|
||||
const u32 magic = *reinterpret_cast<u32*>(buf.get_ptr());
|
||||
|
||||
if (magic != "P3TF"_u32)
|
||||
{
|
||||
return CELL_GAME_ERROR_INVALID_THEME_FILE;
|
||||
}
|
||||
|
||||
if (func && bufSize < fileSize)
|
||||
{
|
||||
cellGame.notice("cellGameThemeInstallFromBuffer: writing theme with func callback to '%s'", dst_path);
|
||||
|
||||
for (u32 file_offset = 0; file_offset < fileSize;)
|
||||
{
|
||||
const u32 read_size = std::min(bufSize, fileSize - file_offset);
|
||||
cellGame.notice("cellGameThemeInstallFromBuffer: writing %d bytes at pos %d", read_size, file_offset);
|
||||
|
||||
if (theme.write(reinterpret_cast<u8*>(buf.get_ptr()) + file_offset, read_size) != read_size)
|
||||
{
|
||||
cellGame.error("cellGameThemeInstallFromBuffer: failed to write to destination file '%s' (error=%s)", dst_path, fs::g_tls_error);
|
||||
|
||||
if (fs::g_tls_error == fs::error::nospace)
|
||||
{
|
||||
return CELL_GAME_ERROR_NOSPACE;
|
||||
}
|
||||
|
||||
return CELL_GAME_ERROR_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
file_offset += read_size;
|
||||
|
||||
// Report status with callback
|
||||
cellGame.notice("cellGameThemeInstallFromBuffer: func(fileOffset=%d, readSize=%d, buf=0x%x)", file_offset, read_size, buf);
|
||||
const s32 result = func(ppu, file_offset, read_size, buf);
|
||||
|
||||
if (result == CELL_GAME_RET_CANCEL) // same as CELL_GAME_CBRESULT_CANCEL
|
||||
{
|
||||
cellGame.notice("cellGameThemeInstallFromBuffer: theme installation was cancelled");
|
||||
return not_an_error(CELL_GAME_RET_CANCEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cellGame.notice("cellGameThemeInstallFromBuffer: writing theme to '%s'", dst_path);
|
||||
|
||||
if (theme.write(buf.get_ptr(), fileSize) != fileSize)
|
||||
{
|
||||
cellGame.error("cellGameThemeInstallFromBuffer: failed to write to destination file '%s' (error=%s)", dst_path, fs::g_tls_error);
|
||||
|
||||
if (fs::g_tls_error == fs::error::nospace)
|
||||
{
|
||||
return CELL_GAME_ERROR_NOSPACE;
|
||||
}
|
||||
|
||||
return CELL_GAME_ERROR_ACCESS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fs::g_tls_error == fs::error::exist) // Do not overwrite files, but continue.
|
||||
{
|
||||
cellGame.notice("cellGameThemeInstallFromBuffer: theme already installed: '%s'", dst_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
cellGame.error("cellGameThemeInstallFromBuffer: failed to open destination file '%s' (error=%s)", dst_path, fs::g_tls_error);
|
||||
return CELL_GAME_ERROR_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
if (option == CELL_GAME_THEME_OPTION_APPLY)
|
||||
{
|
||||
// TODO: apply new theme
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ using CellHddGameSystemFileParam = CellGameDataSystemFileParam;
|
|||
using CellHddGameCBResult = CellGameDataCBResult;
|
||||
|
||||
typedef void(CellHddGameStatCallback)(vm::ptr<CellHddGameCBResult> cbResult, vm::ptr<CellHddGameStatGet> get, vm::ptr<CellHddGameStatSet> set);
|
||||
typedef void(CellGameThemeInstallCallback)(u32 fileOffset, u32 readSize, vm::ptr<void> buf);
|
||||
typedef s32(CellGameThemeInstallCallback)(u32 fileOffset, u32 readSize, vm::ptr<void> buf);
|
||||
typedef void(CellGameDiscEjectCallback)();
|
||||
typedef void(CellGameDiscInsertCallback)(u32 discType, vm::ptr<char> titleId);
|
||||
typedef void(CellDiscGameDiscEjectCallback)();
|
||||
|
|
|
@ -601,7 +601,7 @@ lv2_file::open_result_t lv2_file::open(std::string_view vpath, s32 flags, s32 mo
|
|||
}
|
||||
|
||||
std::string path;
|
||||
const std::string local_path = vfs::get(vpath, nullptr, &path);
|
||||
std::string local_path = vfs::get(vpath, nullptr, &path);
|
||||
|
||||
const auto mp = lv2_fs_object::get_mp(vpath);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "curl_handle.h"
|
||||
#include "progress_dialog.h"
|
||||
|
||||
#include "Crypto/sha256.h"
|
||||
#include "util/logs.hpp"
|
||||
|
||||
LOG_CHANNEL(network_log, "NET");
|
||||
|
@ -156,27 +155,6 @@ progress_dialog* downloader::get_progress_dialog() const
|
|||
return m_progress_dialog;
|
||||
}
|
||||
|
||||
std::string downloader::get_hash(const char* data, usz size, bool lower_case)
|
||||
{
|
||||
u8 res_hash[32];
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts_ret(&ctx, 0);
|
||||
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(data), size);
|
||||
mbedtls_sha256_finish_ret(&ctx, res_hash);
|
||||
|
||||
std::string res_hash_string("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
||||
for (usz index = 0; index < 32; index++)
|
||||
{
|
||||
const auto pal = lower_case ? "0123456789abcdef" : "0123456789ABCDEF";
|
||||
res_hash_string[index * 2] = pal[res_hash[index] >> 4];
|
||||
res_hash_string[(index * 2) + 1] = pal[res_hash[index] & 15];
|
||||
}
|
||||
|
||||
return res_hash_string;
|
||||
}
|
||||
|
||||
usz downloader::update_buffer(char* data, usz size)
|
||||
{
|
||||
if (m_curl_abort)
|
||||
|
|
|
@ -29,8 +29,6 @@ public:
|
|||
|
||||
progress_dialog* get_progress_dialog() const;
|
||||
|
||||
static std::string get_hash(const char* data, usz size, bool lower_case);
|
||||
|
||||
private Q_SLOTS:
|
||||
void handle_buffer_update(int size, int max) const;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "qt_utils.h"
|
||||
#include "Utilities/File.h"
|
||||
#include "util/logs.hpp"
|
||||
#include "Crypto/utils.h"
|
||||
|
||||
LOG_CHANNEL(patch_log, "PAT");
|
||||
|
||||
|
@ -904,7 +905,7 @@ void patch_manager_dialog::download_update(bool automatic, bool auto_accept)
|
|||
{
|
||||
if (const fs::file patch_file{path})
|
||||
{
|
||||
const std::string hash = downloader::get_hash(patch_file.to_string().c_str(), patch_file.size(), true);
|
||||
const std::string hash = sha256_get_hash(patch_file.to_string().c_str(), patch_file.size(), true);
|
||||
url += "&sha256=" + hash;
|
||||
}
|
||||
else
|
||||
|
@ -1006,7 +1007,7 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
|
|||
|
||||
const std::string content = patch.toString().toStdString();
|
||||
|
||||
if (hash_obj.toString().toStdString() != downloader::get_hash(content.c_str(), content.size(), true))
|
||||
if (hash_obj.toString().toStdString() != sha256_get_hash(content.c_str(), content.size(), true))
|
||||
{
|
||||
patch_log.error("JSON content does not match the provided checksum");
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "Utilities/File.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_utils.hpp"
|
||||
#include "Crypto/utils.h"
|
||||
#include "util/logs.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -372,7 +373,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (const std::string res_hash_string = downloader::get_hash(data.data(), data.size(), false);
|
||||
if (const std::string res_hash_string = sha256_get_hash(data.data(), data.size(), false);
|
||||
m_expected_hash != res_hash_string)
|
||||
{
|
||||
update_log.error("Hash mismatch: %s expected: %s", res_hash_string, m_expected_hash);
|
||||
|
|
Loading…
Add table
Reference in a new issue