mirror of
https://github.com/Vita3K/psvpfsparser.git
synced 2024-11-26 23:20:27 +00:00
272 lines
7.4 KiB
C++
272 lines
7.4 KiB
C++
#pragma once
|
|
|
|
//very basics of the format can be found here
|
|
//http://www.vitadevwiki.com/index.php?title=Files.db
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <cstdint>
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <iomanip>
|
|
#include <memory>
|
|
|
|
#include "Utils.h"
|
|
#include "FlagOperations.h"
|
|
#include "IF00DKeyEncryptor.h"
|
|
#include "ICryptoOperations.h"
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
#define MAGIC_WORD "SCENGPFS"
|
|
|
|
#define MAX_FILES_IN_BLOCK 9
|
|
|
|
#define EXPECTED_BLOCK_SIZE 0x400
|
|
|
|
#define FILES_EXPECTED_VERSION_3 3
|
|
#define FILES_EXPECTED_VERSION_4 4 //looks like files.db salt appeared in this version. before that it was 0
|
|
#define FILES_EXPECTED_VERSION_5 5
|
|
|
|
struct sce_ng_pfs_header_t
|
|
{
|
|
std::uint8_t magic[8];
|
|
std::uint32_t version;
|
|
std::uint16_t image_spec; // allows to distinguish unicv.db and icv.db - check is_unicv_to_img_type
|
|
std::uint16_t key_id;
|
|
std::uint32_t pageSize;
|
|
std::uint32_t bt_order; // order value of the binary tree - derived from btree_order
|
|
std::uint32_t root_icv_page_number; // derived from off2pgn or btree_top
|
|
std::uint32_t files_salt; // first salt value used for key derrivation
|
|
std::uint64_t unk6; // is 0xFFFFFFFFFFFFFFFF or rarely may have other unknown value
|
|
std::uint64_t tailSize; // size of data after this header
|
|
std::uint64_t total_sz; // is 0
|
|
std::uint8_t root_icv[0x14]; // 0x38 hmac-sha1 of (pageSize - 4) of page (pointed by root_icv_page_number) with secret derived from klicensee
|
|
std::uint8_t header_icv[0x14]; // 0x4C hmac-sha1 of 0x16 bytes of header with secret derived from klicensee
|
|
std::uint8_t rsa_sig0[0x100];
|
|
std::uint8_t rsa_sig1[0x100];
|
|
std::uint8_t padding[0x1A0];
|
|
};
|
|
|
|
//still have to figure out. not quite clear
|
|
enum sce_ng_pfs_block_types : std::uint32_t
|
|
{
|
|
child = 0,
|
|
root = 1 // if page number is -1 then this should be root. otherwise - unknown
|
|
};
|
|
|
|
struct sce_ng_pfs_block_header_t
|
|
{
|
|
std::uint32_t parent_page_number;
|
|
sce_ng_pfs_block_types type;
|
|
std::uint32_t nFiles;
|
|
std::uint32_t padding; // probably padding ? always 0
|
|
};
|
|
|
|
//there can be 9 files at max in one block
|
|
struct sce_ng_pfs_file_header_t
|
|
{
|
|
std::uint32_t index; //parent index
|
|
std::uint8_t fileName[68];
|
|
};
|
|
|
|
enum sce_ng_pfs_file_types : std::uint16_t
|
|
{
|
|
unexisting = ATTR_RW_OR_NONE, //(0x0000)
|
|
normal_file = ATTR_RO, //(0x0001)
|
|
normal_directory = ATTR_DIR, //(0x8000)
|
|
|
|
sys_directory = ATTR_DIR | ATTR_SYS1 | ATTR_SYS2, //(0x8006)
|
|
|
|
unencrypted_system_file_rw = ATTR_NENC | ATTR_SYS1 | ATTR_SYS2, //(0x4006)
|
|
encrypted_system_file_rw = ATTR_SYS1 | ATTR_SYS2, //(0x0006)
|
|
|
|
unencrypted_system_file_ro = ATTR_NENC | ATTR_SYS1 | ATTR_SYS2 | ATTR_RO, //(0x4007)
|
|
encrypted_system_file_ro = ATTR_SYS1 | ATTR_SYS2 | ATTR_RO, //(0x0007)
|
|
|
|
acid_directory = ATTR_DIR | ATTR_AC | ATTR_SYS2, //(0x9004) encountered in ADDCONT
|
|
};
|
|
|
|
#define INVALID_FILE_INDEX 0xFFFFFFFF
|
|
|
|
struct sce_ng_pfs_file_info_t
|
|
{
|
|
std::uint32_t idx; // this file index. can be INVALID_FILE_INDEX
|
|
sce_ng_pfs_file_types type;
|
|
std::uint16_t padding0; //probably padding ? always 0
|
|
std::uint32_t size;
|
|
std::uint32_t padding1; //probably padding ? always 0
|
|
};
|
|
|
|
struct sce_ng_pfs_file_info_proxy_t
|
|
{
|
|
sce_ng_pfs_file_info_t header;
|
|
sce_ng_pfs_file_types original_type;
|
|
bool hasFixedType;
|
|
|
|
sce_ng_pfs_file_info_proxy_t()
|
|
: hasFixedType(false)
|
|
{
|
|
}
|
|
|
|
sce_ng_pfs_file_types get_original_type() const
|
|
{
|
|
if(hasFixedType)
|
|
return original_type;
|
|
else
|
|
return header.type;
|
|
}
|
|
};
|
|
|
|
struct sce_ng_pfs_hash_t
|
|
{
|
|
std::uint8_t data[20];
|
|
};
|
|
|
|
struct sce_ng_pfs_block_t
|
|
{
|
|
sce_ng_pfs_block_header_t header; //size = 16
|
|
std::vector<sce_ng_pfs_file_header_t> files; // size = 72 * 9 = 648
|
|
|
|
//infos may contain non INVALID_FILE_INDEX as last element
|
|
//still dont know the purpose of this
|
|
std::vector<sce_ng_pfs_file_info_proxy_t> m_infos; // size = 16 * 10 = 160
|
|
std::vector<sce_ng_pfs_hash_t> hashes; // size = 20 * 10 = 200
|
|
|
|
std::uint32_t page;
|
|
};
|
|
|
|
struct sce_ng_pfs_flat_block_t
|
|
{
|
|
sce_ng_pfs_block_header_t header;
|
|
sce_ng_pfs_file_header_t file;
|
|
sce_ng_pfs_file_info_proxy_t m_info;
|
|
sce_ng_pfs_hash_t hash;
|
|
};
|
|
|
|
struct sce_ng_pfs_file_t
|
|
{
|
|
private:
|
|
sce_junction m_path;
|
|
|
|
public:
|
|
sce_ng_pfs_flat_block_t file;
|
|
std::vector<sce_ng_pfs_flat_block_t> dirs;
|
|
|
|
sce_ng_pfs_file_t(const sce_junction& p)
|
|
: m_path(p)
|
|
{
|
|
|
|
}
|
|
|
|
public:
|
|
const sce_junction& path() const
|
|
{
|
|
return m_path;
|
|
}
|
|
};
|
|
|
|
struct sce_ng_pfs_dir_t
|
|
{
|
|
private:
|
|
sce_junction m_path;
|
|
|
|
public:
|
|
sce_ng_pfs_flat_block_t dir;
|
|
std::vector<sce_ng_pfs_flat_block_t> dirs;
|
|
|
|
sce_ng_pfs_dir_t(const sce_junction& p)
|
|
: m_path(p)
|
|
{
|
|
|
|
}
|
|
|
|
public:
|
|
const sce_junction& path() const
|
|
{
|
|
return m_path;
|
|
}
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
bool is_directory(sce_ng_pfs_file_types type);
|
|
|
|
bool is_valid_file_type(sce_ng_pfs_file_types type);
|
|
|
|
bool is_encrypted(sce_ng_pfs_file_types type);
|
|
|
|
bool is_unencrypted(sce_ng_pfs_file_types type);
|
|
|
|
bool is_unexisting(sce_ng_pfs_file_types type);
|
|
|
|
class FilesDbParser
|
|
{
|
|
private:
|
|
std::shared_ptr<ICryptoOperations> m_cryptops;
|
|
std::shared_ptr<IF00DKeyEncryptor> m_iF00D;
|
|
std::ostream& m_output;
|
|
unsigned char m_klicensee[0x10];
|
|
psvpfs::path m_titleIdPath;
|
|
|
|
private:
|
|
sce_ng_pfs_header_t m_header;
|
|
std::vector<sce_ng_pfs_file_t> m_files;
|
|
std::vector<sce_ng_pfs_dir_t> m_dirs;
|
|
|
|
public:
|
|
FilesDbParser(std::shared_ptr<ICryptoOperations> cryptops, std::shared_ptr<IF00DKeyEncryptor> iF00D, std::ostream& output,
|
|
const unsigned char* klicensee, psvpfs::path titleIdPath);
|
|
|
|
private:
|
|
bool verify_header_icv(std::ifstream& inputStream, const unsigned char* secret);
|
|
|
|
bool get_isUnicv(bool& isUnicv);
|
|
|
|
bool validate_header(uint32_t dataSize);
|
|
|
|
bool parseFilesDb(std::ifstream& inputStream, std::vector<sce_ng_pfs_block_t>& blocks);
|
|
|
|
private:
|
|
bool constructDirmatrix(const std::vector<sce_ng_pfs_block_t>& blocks, std::map<std::uint32_t, std::uint32_t>& dirMatrix);
|
|
|
|
bool constructFileMatrix(std::vector<sce_ng_pfs_block_t>& blocks, std::map<std::uint32_t, std::uint32_t>& fileMatrix);
|
|
|
|
bool flattenBlocks(const std::vector<sce_ng_pfs_block_t>& blocks, std::vector<sce_ng_pfs_flat_block_t>& flatBlocks);
|
|
|
|
const std::vector<sce_ng_pfs_flat_block_t>::const_iterator findFlatBlockDir(const std::vector<sce_ng_pfs_flat_block_t>& flatBlocks, std::uint32_t index);
|
|
|
|
const std::vector<sce_ng_pfs_flat_block_t>::const_iterator findFlatBlockFile(const std::vector<sce_ng_pfs_flat_block_t>& flatBlocks, std::uint32_t index);
|
|
|
|
bool constructDirPaths(const std::map<std::uint32_t, std::uint32_t>& dirMatrix, const std::vector<sce_ng_pfs_flat_block_t>& flatBlocks);
|
|
|
|
bool constructFilePaths(const std::map<std::uint32_t, std::uint32_t>& dirMatrix, const std::map<std::uint32_t, std::uint32_t>& fileMatrix, const std::vector<sce_ng_pfs_flat_block_t>& flatBlocks);
|
|
|
|
private:
|
|
bool linkDirpaths(const std::set<psvpfs::path>& real_directories);
|
|
|
|
bool linkFilepaths(const std::set<psvpfs::path>& real_files, std::uint32_t fileSectorSize);
|
|
|
|
int matchFileLists(const std::set<psvpfs::path>& files);
|
|
|
|
public:
|
|
int parse();
|
|
|
|
public:
|
|
const sce_ng_pfs_header_t& get_header() const
|
|
{
|
|
return m_header;
|
|
}
|
|
|
|
const std::vector<sce_ng_pfs_file_t>& get_files() const
|
|
{
|
|
return m_files;
|
|
}
|
|
|
|
const std::vector<sce_ng_pfs_dir_t>& get_dirs() const
|
|
{
|
|
return m_dirs;
|
|
}
|
|
}; |