From 53a0887112ab23e83b869b785672f034bc7883f7 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sat, 2 Jun 2018 21:59:57 +0300 Subject: [PATCH] Allow specialised output in UEFIExtract --- UEFIExtract/ffsdumper.cpp | 78 +++++++++++++++++------------- UEFIExtract/ffsdumper.h | 14 +++++- UEFIExtract/uefiextract_main.cpp | 82 +++++++++++++++++++++++++++----- 3 files changed, 127 insertions(+), 47 deletions(-) diff --git a/UEFIExtract/ffsdumper.cpp b/UEFIExtract/ffsdumper.cpp index 07ee5ca..9399768 100644 --- a/UEFIExtract/ffsdumper.cpp +++ b/UEFIExtract/ffsdumper.cpp @@ -13,10 +13,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "ffsdumper.h" -USTATUS FfsDumper::dump(const QModelIndex & root, const QString & path, const bool dumpAll, const QString & guid) +USTATUS FfsDumper::dump(const QModelIndex & root, const QString & path, const DumpMode dumpMode, const UINT8 sectionType, const QString & guid) { dumped = false; - UINT8 result = recursiveDump(root, path, dumpAll, guid); + + QDir dir; + if (dir.cd(path)) + return U_DIR_ALREADY_EXIST; + + UINT8 result = recursiveDump(root, path, dumpMode, sectionType, guid); if (result) return result; else if (!dumped) @@ -24,7 +29,7 @@ USTATUS FfsDumper::dump(const QModelIndex & root, const QString & path, const bo return U_SUCCESS; } -USTATUS FfsDumper::recursiveDump(const QModelIndex & index, const QString & path, const bool dumpAll, const QString & guid) +USTATUS FfsDumper::recursiveDump(const QModelIndex & index, const QString & path, const DumpMode dumpMode, const UINT8 sectionType, const QString & guid) { if (!index.isValid()) return U_INVALID_PARAMETER; @@ -34,45 +39,50 @@ USTATUS FfsDumper::recursiveDump(const QModelIndex & index, const QString & path guidToUString(*(const EFI_GUID*)model->header(index).constData()) == guid || guidToUString(*(const EFI_GUID*)model->header(model->findParentOfType(index, Types::File)).constData()) == guid) { - if (dir.cd(path)) - return U_DIR_ALREADY_EXIST; - - if (!dir.mkpath(path)) + if (!dir.cd(path) && !dir.mkpath(path)) return U_DIR_CREATE; QFile file; - if (dumpAll || model->rowCount(index) == 0) { // Dump if leaf item or dumpAll is true - if (!model->header(index).isEmpty()) { - file.setFileName(QObject::tr("%1/header.bin").arg(path)); - if (!file.open(QFile::WriteOnly)) - return U_FILE_OPEN; + if (dumpMode == DUMP_ALL || model->rowCount(index) == 0) { // Dump if leaf item or dumpAll is true + if (dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT || dumpMode == DUMP_HEADER) { + if (!model->header(index).isEmpty() && (sectionType == IgnoreSectionType || model->subtype(index) == sectionType)) { + file.setFileName(QObject::tr("%1/header.bin").arg(path)); + if (!file.open(QFile::WriteOnly)) + return U_FILE_OPEN; - file.write(model->header(index)); - file.close(); + file.write(model->header(index)); + file.close(); + } } - if (!model->body(index).isEmpty()) { - file.setFileName(QObject::tr("%1/body.bin").arg(path)); - if (!file.open(QFile::WriteOnly)) - return U_FILE_OPEN; + if (dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT || dumpMode == DUMP_BODY) { + if (!model->body(index).isEmpty() && (sectionType == IgnoreSectionType || model->subtype(index) == sectionType)) { + file.setFileName(QObject::tr("%1/body.bin").arg(path)); + if (!file.open(QFile::WriteOnly)) + return U_FILE_OPEN; - file.write(model->body(index)); - file.close(); + file.write(model->body(index)); + file.close(); + } } } - // Always dump info - QString info = QObject::tr("Type: %1\nSubtype: %2\n%3%4\n") - .arg(itemTypeToUString(model->type(index))) - .arg(itemSubtypeToUString(model->type(index), model->subtype(index))) - .arg(model->text(index).isEmpty() ? QObject::tr("") : QObject::tr("Text: %1\n").arg(model->text(index))) - .arg(model->info(index)); - file.setFileName(QObject::tr("%1/info.txt").arg(path)); - if (!file.open(QFile::Text | QFile::WriteOnly)) - return U_FILE_OPEN; + // Always dump info unless explicitly prohibited + if ((dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT || dumpMode == DUMP_INFO) + && (sectionType == IgnoreSectionType || model->subtype(index) == sectionType)) { + QString info = QObject::tr("Type: %1\nSubtype: %2\n%3%4\n") + .arg(itemTypeToUString(model->type(index))) + .arg(itemSubtypeToUString(model->type(index), model->subtype(index))) + .arg(model->text(index).isEmpty() ? QObject::tr("") : QObject::tr("Text: %1\n").arg(model->text(index))) + .arg(model->info(index)); + file.setFileName(QObject::tr("%1/info.txt").arg(path)); + if (!file.open(QFile::Text | QFile::WriteOnly)) + return U_FILE_OPEN; + + file.write(info.toLatin1()); + file.close(); + } - file.write(info.toLatin1()); - file.close(); dumped = true; } @@ -83,8 +93,10 @@ USTATUS FfsDumper::recursiveDump(const QModelIndex & index, const QString & path if (model->type(childIndex) != Types::Volume) useText = !model->text(childIndex).isEmpty(); - QString childPath = QString("%1/%2 %3").arg(path).arg(i).arg(useText ? model->text(childIndex) : model->name(childIndex)); - result = recursiveDump(childIndex, childPath, dumpAll, guid); + QString childPath = path; + if (dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT) + childPath = QString("%1/%2 %3").arg(path).arg(i).arg(useText ? model->text(childIndex) : model->name(childIndex)); + result = recursiveDump(childIndex, childPath, dumpMode, sectionType, guid); if (result) return result; } diff --git a/UEFIExtract/ffsdumper.h b/UEFIExtract/ffsdumper.h index f45946e..453836a 100644 --- a/UEFIExtract/ffsdumper.h +++ b/UEFIExtract/ffsdumper.h @@ -27,13 +27,23 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. class FfsDumper { public: + enum DumpMode { + DUMP_CURRENT, + DUMP_ALL, + DUMP_BODY, + DUMP_HEADER, + DUMP_INFO + }; + + static const UINT8 IgnoreSectionType = 0xFF; + explicit FfsDumper(TreeModel * treeModel) : model(treeModel), dumped(false) {} ~FfsDumper() {}; - USTATUS dump(const QModelIndex & root, const QString & path, const bool dumpAll = false, const QString & guid = QString()); + USTATUS dump(const QModelIndex & root, const QString & path, const DumpMode dumpMode = DUMP_CURRENT, const UINT8 sectionType = IgnoreSectionType, const QString & guid = QString()); private: - USTATUS recursiveDump(const QModelIndex & root, const QString & path, const bool dumpAll, const QString & guid); + USTATUS recursiveDump(const QModelIndex & root, const QString & path, const DumpMode dumpMode, const UINT8 sectionType, const QString & guid); TreeModel* model; bool dumped; }; diff --git a/UEFIExtract/uefiextract_main.cpp b/UEFIExtract/uefiextract_main.cpp index d2ff70a..208144c 100644 --- a/UEFIExtract/uefiextract_main.cpp +++ b/UEFIExtract/uefiextract_main.cpp @@ -18,6 +18,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "../common/ffsreport.h" #include "ffsdumper.h" +enum ReadType { + READ_INPUT, + READ_OUTPUT, + READ_MODE, + READ_SECTION +}; + int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); @@ -25,11 +32,6 @@ int main(int argc, char *argv[]) a.setOrganizationDomain("longsoft.me"); a.setApplicationName("UEFIExtract"); - if (a.arguments().length() > 32) { - std::cout << "Too many arguments" << std::endl; - return 1; - } - if (a.arguments().length() > 1) { // Check that input file exists QString path = a.arguments().at(1); @@ -87,13 +89,67 @@ int main(int argc, char *argv[]) } else if (a.arguments().length() > 3 || (a.arguments().length() == 3 && a.arguments().at(2) != QString("all") && a.arguments().at(2) != QString("report"))) { // Dump specific files, without report - UINT32 returned = 0; + std::vector inputs, outputs; + std::vector modes; + std::vector sectionTypes; + ReadType readType = READ_INPUT; for (int i = 2; i < a.arguments().length(); i++) { - result = ffsDumper.dump(model.index(0, 0), fileInfo.fileName().append(".dump"), true, a.arguments().at(i)); - if (result) - returned |= (1 << (i - 1)); + QString arg = a.arguments().at(i); + if (arg == QString("-i")) { + readType = READ_INPUT; + continue; + } else if (arg == QString("-o")) { + readType = READ_OUTPUT; + continue; + } else if (arg == QString("-m")) { + readType = READ_MODE; + continue; + } else if (arg == QString("-t")) { + readType = READ_SECTION; + continue; + } + + if (readType == READ_INPUT) { + inputs.push_back(arg); + } else if (readType == READ_OUTPUT) { + outputs.push_back(arg); + } else if (readType == READ_MODE) { + if (arg == QString("all")) + modes.push_back(FfsDumper::DUMP_ALL); + else if (arg == QString("body")) + modes.push_back(FfsDumper::DUMP_BODY); + else if (arg == QString("header")) + modes.push_back(FfsDumper::DUMP_HEADER); + else if (arg == QString("info")) + modes.push_back(FfsDumper::DUMP_INFO); + else + return U_INVALID_PARAMETER; + } else if (readType == READ_SECTION) { + bool converted; + UINT8 sectionType = (UINT8)arg.toUShort(&converted, 16); + if (!converted) + return U_INVALID_PARAMETER; + sectionTypes.push_back(sectionType); + } } - return returned; + if (inputs.empty() || (!outputs.empty() && inputs.size() != outputs.size()) || + (!modes.empty() && inputs.size() != modes.size()) || + (!sectionTypes.empty() && inputs.size() != sectionTypes.size())) + return U_INVALID_PARAMETER; + + USTATUS lastError = U_SUCCESS; + for (size_t i = 0; i < inputs.size(); i++) { + QString outPath = outputs.empty() ? fileInfo.fileName().append(".dump") : outputs[i]; + FfsDumper::DumpMode mode = modes.empty() ? FfsDumper::DUMP_ALL : modes[i]; + UINT8 type = sectionTypes.empty() ? FfsDumper::IgnoreSectionType : sectionTypes[i]; + result = ffsDumper.dump(model.index(0, 0), outPath, mode, type, inputs[i]); + if (result) { + std::cout << "Guid " << inputs[i].toStdString() << " failed with " << result << " code!" << std::endl; + lastError = result; + } + } + + return lastError; } // Create ffsReport @@ -115,7 +171,7 @@ int main(int argc, char *argv[]) return (ffsDumper.dump(model.index(0, 0), fileInfo.fileName().append(".dump")) != U_SUCCESS); } else if (a.arguments().length() == 3 && a.arguments().at(2) == QString("all")) { // Dump every elementm with report - return (ffsDumper.dump(model.index(0, 0), fileInfo.fileName().append(".dump"), true) != U_SUCCESS); + return (ffsDumper.dump(model.index(0, 0), fileInfo.fileName().append(".dump"), FfsDumper::DUMP_ALL) != U_SUCCESS); } else if (a.arguments().length() == 3 && a.arguments().at(2) == QString("report")) { // Skip dumping return 0; @@ -127,7 +183,9 @@ int main(int argc, char *argv[]) << " UEFIExtract imagefile all - generate report and dump all tree items." << std::endl << " UEFIExtract imagefile dump - only generate dump, no report needed." << std::endl << " UEFIExtract imagefile report - only generate report, no dump needed." << std::endl - << " UEFIExtract imagefile GUID_1 GUID_2 ... GUID_31 - dump only FFS file(s) with specific GUID(s), without report." << std::endl + << " UEFIExtract imagefile GUID_1 ... [ -o FILE_1 ... ] [ -m MODE_1 ... ] [ -t TYPE_1 ... ] -" << std::endl + << " Dump only FFS file(s) with specific GUID(s), without report." << std::endl + << " Type is section type or FF to ignore. Mode is one of: all, body, header, info." << std::endl << "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise." << std::endl; return 1; }