Port PfsProcess to libtoolchain

This commit is contained in:
jakcron 2021-10-02 22:53:21 +08:00
parent ab2686fd78
commit 5f1e8b27de
6 changed files with 91 additions and 79 deletions

@ -1 +1 @@
Subproject commit 02c6703c9720d98197b3bb697fdab12008a9829e Subproject commit 17c5c7177d8a899d01826091b3637e133b1f1c8e

View file

@ -1,20 +1,16 @@
#include "PfsProcess.h" #include "PfsProcess.h"
#include "util.h"
#include <iostream>
#include <iomanip>
#include <fnd/SimpleFile.h>
#include <fnd/io.h>
#include <nn/hac/PartitionFsUtil.h> #include <nn/hac/PartitionFsUtil.h>
#include <tc/io/LocalStorage.h>
nstool::PfsProcess::PfsProcess() : nstool::PfsProcess::PfsProcess() :
mModuleName("nstool::PfsProcess"),
mFile(), mFile(),
mCliOutputMode(true, false, false, false), mCliOutputMode(true, false, false, false),
mVerify(false), mVerify(false),
mExtractPath(), mExtractPath(),
mExtract(false),
mMountName(), mMountName(),
mListFs(false), mListFs(false),
mPfs() mPfs()
@ -33,7 +29,7 @@ void nstool::PfsProcess::process()
} }
if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify) if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify)
validateHfs(); validateHfs();
if (mExtract) if (mExtractPath.isSet())
extractFs(); extractFs();
} }
@ -57,9 +53,8 @@ void nstool::PfsProcess::setMountPointName(const std::string& mount_name)
mMountName = mount_name; mMountName = mount_name;
} }
void nstool::PfsProcess::setExtractPath(const std::string& path) void nstool::PfsProcess::setExtractPath(const tc::io::Path& path)
{ {
mExtract = true;
mExtractPath = path; mExtractPath = path;
} }
@ -75,125 +70,126 @@ const nn::hac::PartitionFsHeader& nstool::PfsProcess::getPfsHeader() const
void nstool::PfsProcess::importHeader() void nstool::PfsProcess::importHeader()
{ {
if (mFile == nullptr)
{
throw tc::Exception(mModuleName, "No file reader set.");
}
tc::ByteData scratch; tc::ByteData scratch;
if (*mFile == nullptr) // read base header to determine complete header size
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sPfsHeader)))
{ {
throw tc::Exception(kModuleName, "No file reader set."); throw tc::Exception(mModuleName, "Corrupt PartitionFs: File too small");
} }
// open minimum header to get full header size scratch = tc::ByteData(sizeof(nn::hac::sPfsHeader));
scratch.alloc(sizeof(nn::hac::sPfsHeader)); mFile->seek(0, tc::io::SeekOrigin::Begin);
(*mFile)->read(scratch.data(), 0, scratch.size()); mFile->read(scratch.data(), scratch.size());
if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false)
{ {
throw tc::Exception(kModuleName, "Corrupt Header"); throw tc::Exception(mModuleName, "Corrupt PartitionFs: Header had incorrect struct magic.");
} }
// read complete size header
size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data())); size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data()));
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(pfsHeaderSize))
// open minimum header to get full header size {
scratch.alloc(pfsHeaderSize); throw tc::Exception(mModuleName, "Corrupt PartitionFs: File too small");
(*mFile)->read(scratch.data(), 0, scratch.size()); }
scratch = tc::ByteData(pfsHeaderSize);
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
// process PFS
mPfs.fromBytes(scratch.data(), scratch.size()); mPfs.fromBytes(scratch.data(), scratch.size());
} }
void nstool::PfsProcess::displayHeader() void nstool::PfsProcess::displayHeader()
{ {
std::cout << "[PartitionFS]" << std::endl; fmt::print("[PartitionFS]\n");
std::cout << " Type: " << nn::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType()) << std::endl; fmt::print(" Type: {:s}\n", nn::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType()));
std::cout << " FileNum: " << std::dec << mPfs.getFileList().size() << std::endl; fmt::print(" FileNum: {:d}\n", mPfs.getFileList().size());
if (mMountName.empty() == false) if (mMountName.empty() == false)
{ {
std::cout << " MountPoint: " << mMountName; fmt::print(" MountPoint: {:s}");
if (mMountName.at(mMountName.length()-1) != '/') if (mMountName.at(mMountName.length()-1) != '/')
std::cout << "/"; fmt::print("/");
std::cout << std::endl; fmt::print("\n");
} }
} }
void nstool::PfsProcess::displayFs() void nstool::PfsProcess::displayFs()
{ {
for (size_t i = 0; i < mPfs.getFileList().size(); i++) auto file_list = mPfs.getFileList();
for (auto itr = file_list.begin(); itr != file_list.end(); itr++)
{ {
const nn::hac::PartitionFsHeader::sFile& file = mPfs.getFileList()[i]; fmt::print(" {:s}", itr->name);
std::cout << " " << file.name;
if (mCliOutputMode.show_layout) if (mCliOutputMode.show_layout)
{ {
switch (mPfs.getFsType()) switch (mPfs.getFsType())
{ {
case (nn::hac::PartitionFsHeader::TYPE_PFS0): case (nn::hac::PartitionFsHeader::TYPE_PFS0):
std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")"; fmt::print(" (offset=0x{:x}, size=0x{:x})", itr->offset, itr->size);
break; break;
case (nn::hac::PartitionFsHeader::TYPE_HFS0): case (nn::hac::PartitionFsHeader::TYPE_HFS0):
std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ", hash_protected_size=0x" << file.hash_protected_size << ")"; fmt::print(" (offset=0x{:x}, size=0x{:x}, hash_protected_size=0x{:x})", itr->offset, itr->size, itr->hash_protected_size);
break; break;
} }
} }
std::cout << std::endl; fmt::print("\n");
} }
} }
size_t nstool::PfsProcess::determineHeaderSize(const nn::hac::sPfsHeader* hdr) size_t nstool::PfsProcess::determineHeaderSize(const nn::hac::sPfsHeader* hdr)
{ {
size_t fileEntrySize = 0; size_t fileEntrySize = 0;
if (hdr->st_magic.get() == nn::hac::pfs::kPfsStructMagic) if (hdr->st_magic.unwrap() == nn::hac::pfs::kPfsStructMagic)
fileEntrySize = sizeof(nn::hac::sPfsFile); fileEntrySize = sizeof(nn::hac::sPfsFile);
else else
fileEntrySize = sizeof(nn::hac::sHashedPfsFile); fileEntrySize = sizeof(nn::hac::sHashedPfsFile);
return sizeof(nn::hac::sPfsHeader) + hdr->file_num.get() * fileEntrySize + hdr->name_table_size.get(); return sizeof(nn::hac::sPfsHeader) + hdr->file_num.unwrap() * fileEntrySize + hdr->name_table_size.unwrap();
} }
bool nstool::PfsProcess::validateHeaderMagic(const nn::hac::sPfsHeader* hdr) bool nstool::PfsProcess::validateHeaderMagic(const nn::hac::sPfsHeader* hdr)
{ {
return hdr->st_magic.get() == nn::hac::pfs::kPfsStructMagic || hdr->st_magic.get() == nn::hac::pfs::kHashedPfsStructMagic; return hdr->st_magic.unwrap() == nn::hac::pfs::kPfsStructMagic || hdr->st_magic.unwrap() == nn::hac::pfs::kHashedPfsStructMagic;
} }
void nstool::PfsProcess::validateHfs() void nstool::PfsProcess::validateHfs()
{ {
fnd::sha::sSha256Hash hash; nn::hac::detail::sha256_hash_t hash;
const std::vector<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList(); auto file_list = mPfs.getFileList();
for (size_t i = 0; i < file.size(); i++) for (auto itr = file_list.begin(); itr != file_list.end(); itr++)
{ {
mCache.alloc(file[i].hash_protected_size); tc::ByteData cache = tc::ByteData(tc::io::IOUtil::castInt64ToSize(itr->hash_protected_size));
(*mFile)->read(mCache.data(), file[i].offset, file[i].hash_protected_size); mFile->seek(itr->offset, tc::io::SeekOrigin::Begin);
fnd::sha::Sha256(mCache.data(), file[i].hash_protected_size, hash.bytes); mFile->read(cache.data(), cache.size());
if (hash != file[i].hash) tc::crypto::GenerateSha256Hash(hash.data(), cache.data(), cache.size());
if (hash != itr->hash)
{ {
printf("[WARNING] HFS0 %s%s%s: FAIL (bad hash)\n", !mMountName.empty()? mMountName.c_str() : "", (!mMountName.empty() && mMountName.at(mMountName.length()-1) != '/' )? "/" : "", file[i].name.c_str()); fmt::print("[WARNING] HFS0 {:s}{:s}{:s}: FAIL (bad hash)\n", !mMountName.empty()? mMountName.c_str() : "", (!mMountName.empty() && mMountName.at(mMountName.length()-1) != '/' )? "/" : "", itr->name);
} }
} }
} }
void nstool::PfsProcess::extractFs() void nstool::PfsProcess::extractFs()
{ {
// allocate only when extractDir is invoked // create extract directory
mCache.alloc(kCacheSize); tc::io::LocalStorage fs;
fs.createDirectory(mExtractPath.get());
// make extract dir // extract files
fnd::io::makeDirectory(mExtractPath); tc::ByteData cache_for_extract = tc::ByteData(kCacheSize);
fnd::SimpleFile outFile; auto file_list = mPfs.getFileList();
const std::vector<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList(); for (auto itr = file_list.begin(); itr != file_list.end(); itr++)
std::string file_path;
for (size_t i = 0; i < file.size(); i++)
{ {
file_path.clear(); tc::io::Path extract_path = mExtractPath.get() + itr->name;
fnd::io::appendToPath(file_path, mExtractPath);
fnd::io::appendToPath(file_path, file[i].name);
if (mCliOutputMode.show_basic_info) writeSubStreamToFile(mFile, itr->offset, itr->size, extract_path, cache_for_extract);
printf("extract=[%s]\n", file_path.c_str());
outFile.open(file_path, outFile.Create);
(*mFile)->seek(file[i].offset);
for (size_t j = 0; j < ((file[i].size / kCacheSize) + ((file[i].size % kCacheSize) != 0)); j++)
{
(*mFile)->read(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize));
outFile.write(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize));
}
outFile.close();
} }
} }

View file

@ -25,9 +25,10 @@ public:
const nn::hac::PartitionFsHeader& getPfsHeader() const; const nn::hac::PartitionFsHeader& getPfsHeader() const;
private: private:
const std::string kModuleName = "PfsProcess";
static const size_t kCacheSize = 0x10000; static const size_t kCacheSize = 0x10000;
std::string mModuleName;
std::shared_ptr<tc::io::IStream> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
@ -36,8 +37,6 @@ private:
std::string mMountName; std::string mMountName;
bool mListFs; bool mListFs;
tc::ByteData mCache;
nn::hac::PartitionFsHeader mPfs; nn::hac::PartitionFsHeader mPfs;
void importHeader(); void importHeader();

View file

@ -4,7 +4,7 @@
//#include "GameCardProcess.h" //#include "GameCardProcess.h"
//#include "PfsProcess.h" #include "PfsProcess.h"
//#include "RomfsProcess.h" //#include "RomfsProcess.h"
//#include "NcaProcess.h" //#include "NcaProcess.h"
//#include "MetaProcess.h" //#include "MetaProcess.h"
@ -50,9 +50,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
obj.process(); obj.process();
} }
*/ else*/ if (set.infile.filetype == nstool::Settings::FILE_TYPE_PARTITIONFS || set.infile.filetype == nstool::Settings::FILE_TYPE_NSP)
/*
else if (set.infile.filetype == nstool::Settings::FILE_TYPE_PARTITIONFS || set.infile.filetype == nstool::Settings::FILE_TYPE_NSP)
{ {
nstool::PfsProcess obj; nstool::PfsProcess obj;
@ -66,6 +64,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
obj.process(); obj.process();
} }
/*
else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ROMFS) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ROMFS)
{ {
nstool::RomfsProcess obj; nstool::RomfsProcess obj;
@ -113,8 +112,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
obj.process(); obj.process();
} }
*/
else*/ if (set.infile.filetype == nstool::Settings::FILE_TYPE_CNMT) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_CNMT)
{ {
nstool::CnmtProcess obj; nstool::CnmtProcess obj;

View file

@ -66,21 +66,29 @@ void nstool::processResFile(const std::shared_ptr<tc::io::IStream>& file, std::m
} }
void nstool::writeSubStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, tc::ByteData& cache)
{
writeStreamToStream(std::make_shared<tc::io::SubStream>(tc::io::SubStream(in_stream, offset, length)), std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileMode::OpenOrCreate, tc::io::FileAccess::Write)), cache);
}
void nstool::writeSubStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, size_t cache_size) void nstool::writeSubStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, size_t cache_size)
{ {
writeStreamToStream(std::make_shared<tc::io::SubStream>(tc::io::SubStream(in_stream, offset, length)), std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileMode::OpenOrCreate, tc::io::FileAccess::Write)), cache_size); writeStreamToStream(std::make_shared<tc::io::SubStream>(tc::io::SubStream(in_stream, offset, length)), std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileMode::OpenOrCreate, tc::io::FileAccess::Write)), cache_size);
} }
void nstool::writeStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, const tc::io::Path& out_path, tc::ByteData& cache)
{
writeStreamToStream(in_stream, std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileMode::OpenOrCreate, tc::io::FileAccess::Write)), cache);
}
void nstool::writeStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, const tc::io::Path& out_path, size_t cache_size) void nstool::writeStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, const tc::io::Path& out_path, size_t cache_size)
{ {
writeStreamToStream(in_stream, std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileMode::OpenOrCreate, tc::io::FileAccess::Write)), cache_size); writeStreamToStream(in_stream, std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileMode::OpenOrCreate, tc::io::FileAccess::Write)), cache_size);
} }
void nstool::writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& out_stream, size_t cache_size) void nstool::writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& out_stream, tc::ByteData& cache)
{ {
// iterate thru child files // iterate thru child files
tc::ByteData cache = tc::ByteData(cache_size);
size_t cache_read_len; size_t cache_read_len;
in_stream->seek(0, tc::io::SeekOrigin::Begin); in_stream->seek(0, tc::io::SeekOrigin::Begin);
@ -99,6 +107,12 @@ void nstool::writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stre
} }
} }
void nstool::writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& out_stream, size_t cache_size)
{
tc::ByteData cache = tc::ByteData(cache_size);
writeStreamToStream(in_stream, out_stream, cache);
}
std::string nstool::getTruncatedBytesString(const byte_t* data, size_t len) std::string nstool::getTruncatedBytesString(const byte_t* data, size_t len)
{ {
if (data == nullptr) { return fmt::format(""); } if (data == nullptr) { return fmt::format(""); }

View file

@ -6,10 +6,14 @@ namespace nstool
void processResFile(const std::shared_ptr<tc::io::IStream>& file, std::map<std::string, std::string>& dict); void processResFile(const std::shared_ptr<tc::io::IStream>& file, std::map<std::string, std::string>& dict);
void writeSubStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, tc::ByteData& cache);
void writeSubStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, size_t cache_size = 0x10000); void writeSubStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, size_t cache_size = 0x10000);
void writeStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, const tc::io::Path& out_path, tc::ByteData& cache);
void writeStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, const tc::io::Path& out_path, size_t cache_size = 0x10000); void writeStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, const tc::io::Path& out_path, size_t cache_size = 0x10000);
void writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& out_stream, tc::ByteData& cache);
void writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& out_stream, size_t cache_size = 0x10000); void writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& out_stream, size_t cache_size = 0x10000);
std::string getTruncatedBytesString(const byte_t* data, size_t len); std::string getTruncatedBytesString(const byte_t* data, size_t len);
std::string getTruncatedBytesString(const byte_t* data, size_t len, bool do_not_truncate); std::string getTruncatedBytesString(const byte_t* data, size_t len, bool do_not_truncate);