mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 10:45:28 +00:00
Port PfsProcess to libtoolchain
This commit is contained in:
parent
ab2686fd78
commit
5f1e8b27de
2
deps/libnintendo-hac
vendored
2
deps/libnintendo-hac
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 02c6703c9720d98197b3bb697fdab12008a9829e
|
||||
Subproject commit 17c5c7177d8a899d01826091b3637e133b1f1c8e
|
|
@ -1,20 +1,16 @@
|
|||
#include "PfsProcess.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/io.h>
|
||||
#include "util.h"
|
||||
|
||||
#include <nn/hac/PartitionFsUtil.h>
|
||||
#include <tc/io/LocalStorage.h>
|
||||
|
||||
|
||||
nstool::PfsProcess::PfsProcess() :
|
||||
mModuleName("nstool::PfsProcess"),
|
||||
mFile(),
|
||||
mCliOutputMode(true, false, false, false),
|
||||
mVerify(false),
|
||||
mExtractPath(),
|
||||
mExtract(false),
|
||||
mMountName(),
|
||||
mListFs(false),
|
||||
mPfs()
|
||||
|
@ -33,7 +29,7 @@ void nstool::PfsProcess::process()
|
|||
}
|
||||
if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify)
|
||||
validateHfs();
|
||||
if (mExtract)
|
||||
if (mExtractPath.isSet())
|
||||
extractFs();
|
||||
}
|
||||
|
||||
|
@ -57,9 +53,8 @@ void nstool::PfsProcess::setMountPointName(const std::string& 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;
|
||||
}
|
||||
|
||||
|
@ -75,125 +70,126 @@ const nn::hac::PartitionFsHeader& nstool::PfsProcess::getPfsHeader() const
|
|||
|
||||
void nstool::PfsProcess::importHeader()
|
||||
{
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw tc::Exception(mModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
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.alloc(sizeof(nn::hac::sPfsHeader));
|
||||
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||
|
||||
scratch = tc::ByteData(sizeof(nn::hac::sPfsHeader));
|
||||
mFile->seek(0, tc::io::SeekOrigin::Begin);
|
||||
mFile->read(scratch.data(), scratch.size());
|
||||
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()));
|
||||
|
||||
// open minimum header to get full header size
|
||||
scratch.alloc(pfsHeaderSize);
|
||||
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(pfsHeaderSize))
|
||||
{
|
||||
throw tc::Exception(mModuleName, "Corrupt PartitionFs: File too small");
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void nstool::PfsProcess::displayHeader()
|
||||
{
|
||||
std::cout << "[PartitionFS]" << std::endl;
|
||||
std::cout << " Type: " << nn::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType()) << std::endl;
|
||||
std::cout << " FileNum: " << std::dec << mPfs.getFileList().size() << std::endl;
|
||||
fmt::print("[PartitionFS]\n");
|
||||
fmt::print(" Type: {:s}\n", nn::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType()));
|
||||
fmt::print(" FileNum: {:d}\n", mPfs.getFileList().size());
|
||||
if (mMountName.empty() == false)
|
||||
{
|
||||
std::cout << " MountPoint: " << mMountName;
|
||||
fmt::print(" MountPoint: {:s}");
|
||||
if (mMountName.at(mMountName.length()-1) != '/')
|
||||
std::cout << "/";
|
||||
std::cout << std::endl;
|
||||
fmt::print("/");
|
||||
fmt::print("\n");
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
std::cout << " " << file.name;
|
||||
fmt::print(" {:s}", itr->name);
|
||||
if (mCliOutputMode.show_layout)
|
||||
{
|
||||
switch (mPfs.getFsType())
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
std::cout << std::endl;
|
||||
fmt::print("\n");
|
||||
}
|
||||
}
|
||||
|
||||
size_t nstool::PfsProcess::determineHeaderSize(const nn::hac::sPfsHeader* hdr)
|
||||
{
|
||||
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);
|
||||
else
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
fnd::sha::sSha256Hash hash;
|
||||
const std::vector<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList();
|
||||
for (size_t i = 0; i < file.size(); i++)
|
||||
nn::hac::detail::sha256_hash_t hash;
|
||||
auto file_list = mPfs.getFileList();
|
||||
for (auto itr = file_list.begin(); itr != file_list.end(); itr++)
|
||||
{
|
||||
mCache.alloc(file[i].hash_protected_size);
|
||||
(*mFile)->read(mCache.data(), file[i].offset, file[i].hash_protected_size);
|
||||
fnd::sha::Sha256(mCache.data(), file[i].hash_protected_size, hash.bytes);
|
||||
if (hash != file[i].hash)
|
||||
tc::ByteData cache = tc::ByteData(tc::io::IOUtil::castInt64ToSize(itr->hash_protected_size));
|
||||
mFile->seek(itr->offset, tc::io::SeekOrigin::Begin);
|
||||
mFile->read(cache.data(), cache.size());
|
||||
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()
|
||||
{
|
||||
// allocate only when extractDir is invoked
|
||||
mCache.alloc(kCacheSize);
|
||||
// create extract directory
|
||||
tc::io::LocalStorage fs;
|
||||
fs.createDirectory(mExtractPath.get());
|
||||
|
||||
// make extract dir
|
||||
fnd::io::makeDirectory(mExtractPath);
|
||||
// extract files
|
||||
tc::ByteData cache_for_extract = tc::ByteData(kCacheSize);
|
||||
|
||||
fnd::SimpleFile outFile;
|
||||
const std::vector<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList();
|
||||
|
||||
std::string file_path;
|
||||
for (size_t i = 0; i < file.size(); i++)
|
||||
auto file_list = mPfs.getFileList();
|
||||
for (auto itr = file_list.begin(); itr != file_list.end(); itr++)
|
||||
{
|
||||
file_path.clear();
|
||||
fnd::io::appendToPath(file_path, mExtractPath);
|
||||
fnd::io::appendToPath(file_path, file[i].name);
|
||||
tc::io::Path extract_path = mExtractPath.get() + itr->name;
|
||||
|
||||
if (mCliOutputMode.show_basic_info)
|
||||
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();
|
||||
writeSubStreamToFile(mFile, itr->offset, itr->size, extract_path, cache_for_extract);
|
||||
}
|
||||
}
|
|
@ -25,9 +25,10 @@ public:
|
|||
const nn::hac::PartitionFsHeader& getPfsHeader() const;
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "PfsProcess";
|
||||
static const size_t kCacheSize = 0x10000;
|
||||
|
||||
std::string mModuleName;
|
||||
|
||||
std::shared_ptr<tc::io::IStream> mFile;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
@ -36,8 +37,6 @@ private:
|
|||
std::string mMountName;
|
||||
bool mListFs;
|
||||
|
||||
tc::ByteData mCache;
|
||||
|
||||
nn::hac::PartitionFsHeader mPfs;
|
||||
|
||||
void importHeader();
|
||||
|
|
11
src/main.cpp
11
src/main.cpp
|
@ -4,7 +4,7 @@
|
|||
|
||||
|
||||
//#include "GameCardProcess.h"
|
||||
//#include "PfsProcess.h"
|
||||
#include "PfsProcess.h"
|
||||
//#include "RomfsProcess.h"
|
||||
//#include "NcaProcess.h"
|
||||
//#include "MetaProcess.h"
|
||||
|
@ -50,9 +50,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
|
||||
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;
|
||||
|
||||
|
@ -66,6 +64,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
|
||||
obj.process();
|
||||
}
|
||||
/*
|
||||
else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ROMFS)
|
||||
{
|
||||
nstool::RomfsProcess obj;
|
||||
|
@ -113,8 +112,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
|
||||
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;
|
||||
|
||||
|
|
18
src/util.cpp
18
src/util.cpp
|
@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
tc::ByteData cache = tc::ByteData(cache_size);
|
||||
size_t cache_read_len;
|
||||
|
||||
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)
|
||||
{
|
||||
if (data == nullptr) { return fmt::format(""); }
|
||||
|
|
|
@ -6,10 +6,14 @@ namespace nstool
|
|||
|
||||
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 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 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);
|
||||
|
||||
|
||||
std::string getTruncatedBytesString(const byte_t* data, size_t len);
|
||||
std::string getTruncatedBytesString(const byte_t* data, size_t len, bool do_not_truncate);
|
||||
|
||||
|
|
Loading…
Reference in a new issue