rpcsx/rpcs3/Loader/TRP.cpp

192 lines
3.5 KiB
C++
Raw Normal View History

2020-12-05 13:08:24 +01:00
#include "stdafx.h"
#include "Emu/VFS.h"
#include "TRP.h"
#include "Crypto/sha1.h"
2018-10-10 06:59:33 +02:00
#include "Utilities/StrUtil.h"
LOG_CHANNEL(trp_log, "Trophy");
2020-02-01 05:36:53 +01:00
2016-02-01 22:47:09 +01:00
TRPLoader::TRPLoader(const fs::file& f)
: trp_f(f)
{
}
2021-03-05 20:05:37 +01:00
bool TRPLoader::Install(const std::string& dest, bool /*show*/)
{
2016-02-01 22:47:09 +01:00
if (!trp_f)
2015-07-26 10:14:56 +02:00
{
fs::g_tls_error = fs::error::noent;
return false;
2015-07-26 10:14:56 +02:00
}
fs::g_tls_error = {};
2016-02-01 22:47:09 +01:00
const std::string& local_path = vfs::get(dest);
const auto temp = fmt::format(u8"%s.temp%u", local_path, utils::get_unique_tsc());
if (!fs::create_dir(temp))
2015-07-15 15:21:41 +02:00
{
2016-02-01 22:47:09 +01:00
return false;
2015-07-15 15:21:41 +02:00
}
2020-09-22 20:29:08 +02:00
// Save TROPUSR.DAT
2020-09-23 04:47:54 +02:00
fs::copy_file(local_path + "/TROPUSR.DAT", temp + "/TROPUSR.DAT", false);
2020-09-22 20:29:08 +02:00
std::vector<char> buffer(65536);
2016-02-01 22:47:09 +01:00
bool success = true;
for (const TRPEntry& entry : m_entries)
{
2016-02-01 22:47:09 +01:00
trp_f.seek(entry.offset);
if (!trp_f.read<true>(buffer, entry.size))
{
trp_log.error("Failed to read TRPEntry at: offset=0x%x, size=0x%x", entry.offset, entry.size);
continue; // ???
}
// Create the file in the temporary directory
success = fs::write_file<true>(temp + '/' + vfs::escape(entry.name), fs::create + fs::excl, buffer);
if (!success)
{
break;
}
}
if (success)
{
success = fs::remove_all(local_path) || !fs::is_dir(local_path);
if (success)
{
// Atomically create trophy data (overwrite existing data)
success = fs::rename(temp, local_path, false);
}
}
if (!success)
{
// Remove temporary directory manually on failure (removed automatically on success)
auto old_error = fs::g_tls_error;
fs::remove_all(temp);
fs::g_tls_error = old_error;
}
return success;
}
bool TRPLoader::LoadHeader(bool show)
{
2016-02-01 22:47:09 +01:00
if (!trp_f)
2015-07-26 10:14:56 +02:00
{
return false;
2015-07-26 10:14:56 +02:00
}
2016-02-01 22:47:09 +01:00
trp_f.seek(0);
2015-07-26 10:14:56 +02:00
2016-02-01 22:47:09 +01:00
if (!trp_f.read(m_header))
2015-07-26 10:14:56 +02:00
{
return false;
2015-07-26 10:14:56 +02:00
}
if (m_header.trp_magic != 0xDCA24D00)
2015-07-26 10:14:56 +02:00
{
return false;
2015-07-26 10:14:56 +02:00
}
if (show)
2015-07-26 10:14:56 +02:00
{
2020-02-01 05:36:53 +01:00
trp_log.notice("TRP version: 0x%x", m_header.trp_version);
2015-07-26 10:14:56 +02:00
}
if (m_header.trp_version >= 2)
{
unsigned char hash[20];
std::vector<u8> file_contents;
trp_f.seek(0);
if (!trp_f.read<true>(file_contents, m_header.trp_file_size))
{
2020-02-01 05:36:53 +01:00
trp_log.notice("Failed verifying checksum");
}
else
{
memset(&(reinterpret_cast<TRPHeader*>(file_contents.data()))->sha1, 0, 20);
sha1(reinterpret_cast<const unsigned char*>(file_contents.data()), m_header.trp_file_size, hash);
if (memcmp(hash, m_header.sha1, 20) != 0)
{
2020-02-01 05:36:53 +01:00
trp_log.error("Invalid checksum of TROPHY.TRP file");
return false;
}
}
trp_f.seek(sizeof(m_header));
}
m_entries.clear();
if (!trp_f.read<true>(m_entries, m_header.trp_files_count))
{
return false;
}
if (show)
{
for (const auto& entry : m_entries)
2015-07-26 10:14:56 +02:00
{
trp_log.notice("TRP entry #%u: %s", &entry - m_entries.data(), entry.name);
2015-07-26 10:14:56 +02:00
}
}
return true;
}
u64 TRPLoader::GetRequiredSpace() const
{
const u64 file_size = m_header.trp_file_size;
const u64 file_element_size = u64{1} * m_header.trp_files_count * m_header.trp_element_size;
return file_size - sizeof(m_header) - file_element_size;
}
bool TRPLoader::ContainsEntry(const char *filename)
{
2015-07-26 10:14:56 +02:00
for (const TRPEntry& entry : m_entries)
{
if (!strcmp(entry.name, filename))
2015-07-26 10:14:56 +02:00
{
return true;
2015-07-26 10:14:56 +02:00
}
}
return false;
}
void TRPLoader::RemoveEntry(const char *filename)
{
std::vector<TRPEntry>::iterator i = m_entries.begin();
2015-07-26 10:14:56 +02:00
while (i != m_entries.end())
{
if (!strcmp(i->name, filename))
2015-07-26 10:14:56 +02:00
{
i = m_entries.erase(i);
2015-07-26 10:14:56 +02:00
}
else
2015-07-26 10:14:56 +02:00
{
i++;
2015-07-26 10:14:56 +02:00
}
}
}
void TRPLoader::RenameEntry(const char *oldname, const char *newname)
{
2018-10-10 06:59:33 +02:00
for (TRPEntry& entry : m_entries)
2015-07-26 10:14:56 +02:00
{
if (!strcmp(entry.name, oldname))
2015-07-26 10:14:56 +02:00
{
2020-03-04 15:08:40 +01:00
strcpy_trunc(entry.name, std::string_view(newname));
2015-07-26 10:14:56 +02:00
}
}
}