mirror of
https://github.com/Vita3K/psvpfsparser.git
synced 2025-02-17 03:28:42 +00:00
167 lines
5.0 KiB
C++
167 lines
5.0 KiB
C++
#include "PfsFilesystem.h"
|
|
|
|
#include "PfsFile.h"
|
|
|
|
#include <cstring>
|
|
|
|
PfsFilesystem::PfsFilesystem(std::shared_ptr<ICryptoOperations> cryptops, std::shared_ptr<IF00DKeyEncryptor> iF00D, std::ostream& output,
|
|
const unsigned char* klicensee, const psvpfs::path& titleIdPath)
|
|
: m_cryptops(cryptops), m_iF00D(iF00D), m_output(output), m_titleIdPath(titleIdPath)
|
|
{
|
|
memcpy(m_klicensee, klicensee, 0x10);
|
|
|
|
m_filesDbParser = std::unique_ptr<FilesDbParser>(new FilesDbParser(cryptops, iF00D, output, klicensee, titleIdPath));
|
|
|
|
m_unicvDbParser = std::unique_ptr<UnicvDbParser>(new UnicvDbParser(titleIdPath, output));
|
|
|
|
m_pageMapper = std::unique_ptr<PfsPageMapper>(new PfsPageMapper(cryptops, iF00D, output, klicensee, titleIdPath));
|
|
}
|
|
|
|
int PfsFilesystem::mount()
|
|
{
|
|
if(m_filesDbParser->parse() < 0)
|
|
return -1;
|
|
|
|
if(m_unicvDbParser->parse() < 0)
|
|
return -1;
|
|
|
|
if(m_pageMapper->bruteforce_map(m_filesDbParser, m_unicvDbParser) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void to_uppercase(std::string &str) {
|
|
std::transform(str.begin(), str.end(), str.begin(), static_cast<int (*)(int)>(std::toupper));
|
|
}
|
|
|
|
int PfsFilesystem::decrypt_files(const psvpfs::path& destTitleIdPath) const
|
|
{
|
|
const sce_ng_pfs_header_t& ngpfs = m_filesDbParser->get_header();
|
|
const std::vector<sce_ng_pfs_file_t>& files = m_filesDbParser->get_files();
|
|
const std::vector<sce_ng_pfs_dir_t>& dirs = m_filesDbParser->get_dirs();
|
|
|
|
const std::unique_ptr<sce_idb_base_t>& unicv = m_unicvDbParser->get_idatabase();
|
|
|
|
const std::map<std::uint32_t, sce_junction>& pageMap = m_pageMapper->get_pageMap();
|
|
const std::set<sce_junction>& emptyFiles = m_pageMapper->get_emptyFiles();
|
|
|
|
std::map<std::string, const sce_ng_pfs_file_t *> file_map;
|
|
for (const auto &file : files) {
|
|
std::string path = file.path().get_value().string();
|
|
to_uppercase(path);
|
|
|
|
file_map[path] = &file;
|
|
}
|
|
|
|
m_output << "Creating directories..." << std::endl;
|
|
|
|
for(auto& d : dirs)
|
|
{
|
|
if(!d.path().create_empty_directory(m_titleIdPath, destTitleIdPath))
|
|
{
|
|
m_output << "Failed to create: " << d.path() << std::endl;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
m_output << "Created: " << d.path() << std::endl;
|
|
}
|
|
}
|
|
|
|
m_output << "Creating empty files..." << std::endl;
|
|
|
|
for(auto& f : emptyFiles)
|
|
{
|
|
std::string path = f.get_value().string();
|
|
to_uppercase(path);
|
|
auto file = file_map.find(path);
|
|
if (file == file_map.end())
|
|
{
|
|
m_output << "Ignored: " << f << std::endl;
|
|
}
|
|
else
|
|
{
|
|
if(!f.create_empty_file(m_titleIdPath, destTitleIdPath))
|
|
{
|
|
m_output << "Failed to create: " << f << std::endl;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
m_output << "Created: " << f << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_output << "Decrypting files..." << std::endl;
|
|
|
|
for(auto& t : unicv->m_tables)
|
|
{
|
|
//skip empty files and directories
|
|
if(t->get_header()->get_numSectors() == 0)
|
|
continue;
|
|
|
|
//find filepath by salt (filename for icv.db or page for unicv.db)
|
|
auto map_entry = pageMap.find(t->get_icv_salt());
|
|
if(map_entry == pageMap.end())
|
|
{
|
|
m_output << "failed to find page " << t->get_icv_salt() << " in map" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
//find file in files.db by filepath
|
|
sce_junction filepath = map_entry->second;
|
|
std::string path = filepath.get_value().string();
|
|
to_uppercase(path);
|
|
auto file_ptr = file_map.find(path);
|
|
if (file_ptr == file_map.end())
|
|
{
|
|
m_output << "failed to find file " << filepath << " in flat file list" << std::endl;
|
|
return -1;
|
|
}
|
|
auto &file = file_ptr->second;
|
|
|
|
//directory and unexisting file are unexpected
|
|
if(is_directory(file->file.m_info.header.type) || is_unexisting(file->file.m_info.header.type))
|
|
{
|
|
m_output << "Unexpected file type" << std::endl;
|
|
return -1;
|
|
}
|
|
//copy unencrypted files
|
|
else if(is_unencrypted(file->file.m_info.header.type))
|
|
{
|
|
if(!filepath.copy_existing_file(m_titleIdPath, destTitleIdPath, file->file.m_info.header.size))
|
|
{
|
|
m_output << "Failed to copy: " << filepath << std::endl;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
m_output << "Copied: " << filepath << std::endl;
|
|
}
|
|
}
|
|
//decrypt encrypted files
|
|
else if(is_encrypted(file->file.m_info.header.type))
|
|
{
|
|
PfsFile pfsFile(m_cryptops, m_iF00D, m_output, m_klicensee, m_titleIdPath, *file, filepath, ngpfs, t);
|
|
|
|
if(pfsFile.decrypt_file(destTitleIdPath) < 0)
|
|
{
|
|
m_output << "Failed to decrypt: " << filepath << std::endl;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
m_output << "Decrypted: " << filepath << std::endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_output << "Unexpected file type" << std::endl;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
} |