pmt: reformat code

This commit is contained in:
2025-08-10 18:44:58 +03:00
parent 787a2e4e46
commit f5e465b995
29 changed files with 12503 additions and 10715 deletions

288
.clang-format Normal file
View File

@@ -0,0 +1,288 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: BinPack
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: MultiLine
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: true
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...

18344
include/CLI/CLI11.hpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

134
include/PartitionManager/PartitionManager.hpp Executable file → Normal file
View File

@@ -17,105 +17,109 @@
#ifndef LIBPMT_LIB_HPP #ifndef LIBPMT_LIB_HPP
#define LIBPMT_LIB_HPP #define LIBPMT_LIB_HPP
#include <string>
#include <vector>
#include <memory>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
#include <memory>
#include <string>
#include <vector>
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include <CLI/CLI11.hpp> #include <CLI/CLI11.hpp>
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#define PMT "libpmt" #define PMT "libpmt"
#define PMTE "pmt" #define PMTE "pmt"
#define PMTF "libpmt-function-manager" #define PMTF "libpmt-function-manager"
namespace PartitionManager { namespace PartitionManager {
// All function classes must inherit from this class. // All function classes must inherit from this class.
class basic_function { class basic_function {
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
virtual bool init(CLI::App &_app) = 0; virtual bool init(CLI::App &_app) = 0;
virtual bool run() = 0; virtual bool run() = 0;
[[nodiscard]] virtual bool isUsed() const = 0; [[nodiscard]] virtual bool isUsed() const = 0;
[[nodiscard]] virtual const char *name() const = 0; [[nodiscard]] virtual const char *name() const = 0;
virtual ~basic_function() = default; virtual ~basic_function() = default;
}; };
// A class for function management. // A class for function management.
class basic_function_manager final { class basic_function_manager final {
private: private:
std::vector<std::unique_ptr<basic_function> > _functions; std::vector<std::unique_ptr<basic_function>> _functions;
public: public:
void registerFunction(std::unique_ptr<basic_function> _func, CLI::App &_app); void registerFunction(std::unique_ptr<basic_function> _func, CLI::App &_app);
[[nodiscard]] bool handleAll() const; [[nodiscard]] bool handleAll() const;
}; };
class basic_variables final { class basic_variables final {
public: public:
basic_variables(); basic_variables();
~basic_variables(); ~basic_variables();
PartitionMap::BuildMap *PartMap; PartitionMap::BuildMap *PartMap;
std::string searchPath, logFile; std::string searchPath, logFile;
bool onLogical; bool onLogical;
bool quietProcess; bool quietProcess;
bool verboseMode; bool verboseMode;
bool viewVersion; bool viewVersion;
bool forceProcess; bool forceProcess;
}; };
class variableProtect final { class variableProtect final {
private: private:
basic_variables* _ptr = nullptr; basic_variables *_ptr = nullptr;
public: public:
variableProtect(); variableProtect();
~variableProtect(); ~variableProtect();
void setVariablePointer(basic_variables* &_ptr); void setVariablePointer(basic_variables *&_ptr);
}; };
using FunctionBase = basic_function; using FunctionBase = basic_function;
using FunctionManager = basic_function_manager; using FunctionManager = basic_function_manager;
using VariableTable = basic_variables; using VariableTable = basic_variables;
using Error = Helper::Error; using Error = Helper::Error;
extern VariableTable *Variables; extern VariableTable *Variables;
int Main(int argc, char **argv); int Main(int argc, char **argv);
// Print messages if not using quiet mode // Print messages if not using quiet mode
__attribute__((format(printf, 1, 2))) __attribute__((format(printf, 1, 2))) void print(const char *format, ...);
void print(const char *format, ...); __attribute__((format(printf, 1, 2))) void println(const char *format, ...);
__attribute__((format(printf, 1, 2)))
void println(const char *format, ...);
// Format it input and return as std::string // Format it input and return as std::string
__attribute__((format(printf, 1, 2))) __attribute__((format(printf, 1, 2))) std::string format(const char *format,
std::string format(const char *format, ...); ...);
// If there is a delimiter in the string, CLI::detail::split returns; if not, an empty vector is returned. And checks duplicate arguments. // If there is a delimiter in the string, CLI::detail::split returns; if not, an
std::vector<std::string> splitIfHasDelim(const std::string &s, char delim, bool checkForBadUsage = false); // empty vector is returned. And checks duplicate arguments.
std::vector<std::string> splitIfHasDelim(const std::string &s, char delim,
bool checkForBadUsage = false);
// Process vectors with input strings. Use for [flag(s)]-[other flag(s)] situations // Process vectors with input strings. Use for [flag(s)]-[other flag(s)]
void processCommandLine(std::vector<std::string> &vec1, std::vector<std::string> &vec2, const std::string &s1, // situations
const std::string &s2, char delim, bool checkForBadUsage = false); void processCommandLine(std::vector<std::string> &vec1,
std::vector<std::string> &vec2, const std::string &s1,
const std::string &s2, char delim,
bool checkForBadUsage = false);
// Setting ups buffer size // Setting ups buffer size
void setupBufferSize(int &size, const std::string &partition); void setupBufferSize(int &size, const std::string &partition);
std::string getLibVersion(); std::string getLibVersion();
std::string getAppVersion(); // Not Android app version (an Android app is planned!), tells pmt version. std::string getAppVersion(); // Not Android app version (an Android app is
// planned!), tells pmt version.
} // namespace PartitionManager } // namespace PartitionManager
#endif // #ifndef LIBPMT_LIB_HPP #endif // #ifndef LIBPMT_LIB_HPP

103
src/FunctionManager.cpp Executable file → Normal file
View File

@@ -14,63 +14,76 @@
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/PartitionManager.hpp>
#include <fcntl.h> #include <fcntl.h>
#include <vector>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
#include <PartitionManager/PartitionManager.hpp> #include <vector>
namespace PartitionManager { namespace PartitionManager {
std::vector<std::string> splitIfHasDelim(const std::string &s, const char delim, const bool checkForBadUsage) { std::vector<std::string> splitIfHasDelim(const std::string &s, const char delim,
if (s.find(delim) == std::string::npos) return {}; const bool checkForBadUsage) {
auto vec = CLI::detail::split(s, delim); if (s.find(delim) == std::string::npos) return {};
auto vec = CLI::detail::split(s, delim);
if (checkForBadUsage) { if (checkForBadUsage) {
std::unordered_set<std::string> set; std::unordered_set<std::string> set;
for (const auto &str: vec) { for (const auto &str : vec) {
if (set.find(str) != set.end()) throw CLI::ValidationError("Duplicate element in your inputs!"); if (set.find(str) != set.end())
set.insert(str); throw CLI::ValidationError("Duplicate element in your inputs!");
} set.insert(str);
} }
}
return vec; return vec;
} }
void setupBufferSize(int &size, const std::string &partition) { void setupBufferSize(int &size, const std::string &partition) {
if (Variables->PartMap->sizeOf(partition) % size != 0) { if (Variables->PartMap->sizeOf(partition) % size != 0) {
print("%sWARNING%s: Specified buffer size is invalid! Using 1 byte as buffer size.", YELLOW, STYLE_RESET); print("%sWARNING%s: Specified buffer size is invalid! Using 1 byte as "
size = 1; "buffer size.",
} YELLOW, STYLE_RESET);
} size = 1;
}
}
void processCommandLine(std::vector<std::string> &vec1, std::vector<std::string> &vec2, const std::string &s1, void processCommandLine(std::vector<std::string> &vec1,
const std::string &s2, const char delim, const bool checkForBadUsage) { std::vector<std::string> &vec2, const std::string &s1,
vec1 = splitIfHasDelim(s1, delim, checkForBadUsage); const std::string &s2, const char delim,
vec2 = splitIfHasDelim(s2, delim, checkForBadUsage); const bool checkForBadUsage) {
vec1 = splitIfHasDelim(s1, delim, checkForBadUsage);
vec2 = splitIfHasDelim(s2, delim, checkForBadUsage);
if (vec1.empty() && !s1.empty()) vec1.push_back(s1); if (vec1.empty() && !s1.empty()) vec1.push_back(s1);
if (vec2.empty() && !s2.empty()) vec2.push_back(s2); if (vec2.empty() && !s2.empty()) vec2.push_back(s2);
} }
void basic_function_manager::registerFunction(std::unique_ptr<basic_function> _func, CLI::App &_app) { void basic_function_manager::registerFunction(
LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl; std::unique_ptr<basic_function> _func, CLI::App &_app) {
if (!_func->init(_app)) throw Error("Cannot init function: %s\n", _func->name()); LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl;
_functions.push_back(std::move(_func)); if (!_func->init(_app))
LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered." << std::endl; throw Error("Cannot init function: %s\n", _func->name());
} _functions.push_back(std::move(_func));
LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered."
<< std::endl;
}
bool basic_function_manager::handleAll() const { bool basic_function_manager::handleAll() const {
LOGN(PMTF, INFO) << "running caught function commands in command-line." << std::endl; LOGN(PMTF, INFO) << "running caught function commands in command-line."
for (const auto &func: _functions) { << std::endl;
if (func->isUsed()) { for (const auto &func : _functions) {
LOGN(PMTF, INFO) << func->name() << " is calling because used in command-line." << std::endl; if (func->isUsed()) {
return func->run(); LOGN(PMTF, INFO) << func->name()
} << " is calling because used in command-line."
} << std::endl;
return func->run();
}
}
LOGN(PMTF, INFO) << "not found any used function from command-line." << std::endl; LOGN(PMTF, INFO) << "not found any used function from command-line."
println("Target progress is not specified. Specify a progress."); << std::endl;
return false; println("Target progress is not specified. Specify a progress.");
} return false;
}
} // namespace PartitionManager } // namespace PartitionManager

9
src/Main.cpp Executable file → Normal file
View File

@@ -16,9 +16,8 @@
#include <PartitionManager/PartitionManager.hpp> #include <PartitionManager/PartitionManager.hpp>
int main(int argc, char** argv) int main(int argc, char **argv) {
{ // Call integrated main function in library
// Call integrated main function in library Helper::LoggingProperties::setProgramName(PMTE);
Helper::LoggingProperties::setProgramName(PMTE); return PartitionManager::Main(argc, argv);
return PartitionManager::Main(argc, argv);
} }

223
src/PartitionManager.cpp Executable file → Normal file
View File

@@ -14,125 +14,152 @@
limitations under the License. limitations under the License.
*/ */
#include <string> #include "functions/functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstdarg>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include <generated/buildInfo.hpp> #include <generated/buildInfo.hpp>
#include "functions/functions.hpp" #include <string>
#include <unistd.h>
namespace PartitionManager { namespace PartitionManager {
variableProtect protector; variableProtect protector;
auto Variables = new VariableTable(); auto Variables = new VariableTable();
variableProtect::variableProtect() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); } variableProtect::variableProtect() {
variableProtect::~variableProtect() { delete _ptr; } Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log");
void variableProtect::setVariablePointer(basic_variables *&_ptr) { this->_ptr = _ptr; } }
variableProtect::~variableProtect() { delete _ptr; }
void variableProtect::setVariablePointer(basic_variables *&_ptr) {
this->_ptr = _ptr;
}
basic_variables::~basic_variables() { delete PartMap; } basic_variables::~basic_variables() { delete PartMap; }
basic_variables::basic_variables() : PartMap(new PartitionMap::BuildMap()), basic_variables::basic_variables()
logFile("/sdcard/Documents/last_pmt_logs.log"), : PartMap(new PartitionMap::BuildMap()),
onLogical(false), logFile("/sdcard/Documents/last_pmt_logs.log"), onLogical(false),
quietProcess(false), quietProcess(false), verboseMode(false), viewVersion(false),
verboseMode(false), forceProcess(false) {}
viewVersion(false),
forceProcess(false)
{}
int Main(int argc, char **argv) { int Main(int argc, char **argv) {
try { try {
// try-catch start // try-catch start
CLI::App AppMain{"Partition Manager Tool"}; CLI::App AppMain{"Partition Manager Tool"};
protector.setVariablePointer(Variables); protector.setVariablePointer(Variables);
FunctionManager FuncManager; FunctionManager FuncManager;
AppMain.fallthrough(true); AppMain.fallthrough(true);
AppMain.set_help_all_flag("--help-all", "Print full help message and exit"); AppMain.set_help_all_flag("--help-all", "Print full help message and exit");
AppMain.footer("Partition Manager Tool is written by YZBruh\nThis project licensed under Apache 2.0 license\nReport bugs to https://github.com/ShawkTeam/pmt-renovated/issues"); AppMain.footer("Partition Manager Tool is written by YZBruh\nThis project "
AppMain.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check( "licensed under "
[&](const std::string &val) { "Apache 2.0 license\nReport "
if (val.find("/block") == std::string::npos) throw CLI::ValidationError( "bugs to https://github.com/ShawkTeam/pmt-renovated/issues");
"Partition search path is unexpected! Couldn't find 'block' in input path!"); AppMain
return std::string(); .add_option("-S,--search-path", Variables->searchPath,
}); "Set partition search path")
AppMain.add_option("-L,--log-file", Variables->logFile, "Set log file"); ->check([&](const std::string &val) {
AppMain.add_flag("-f,--force", Variables->forceProcess, "Force process to be processed"); if (val.find("/block") == std::string::npos)
AppMain.add_flag("-l,--logical", Variables->onLogical, "Specify that the target partition is dynamic"); throw CLI::ValidationError(
AppMain.add_flag("-q,--quiet", Variables->quietProcess, "Quiet process"); "Partition search path is unexpected! Couldn't find "
AppMain.add_flag("-V,--verbose", Variables->verboseMode, "'block' in input path!");
"Detailed information is written on the screen while the transaction is being carried out"); return std::string();
AppMain.add_flag("-v,--version", Variables->viewVersion, "Print version and exit"); });
AppMain.add_option("-L,--log-file", Variables->logFile, "Set log file");
AppMain.add_flag("-f,--force", Variables->forceProcess,
"Force process to be processed");
AppMain.add_flag("-l,--logical", Variables->onLogical,
"Specify that the target partition is dynamic");
AppMain.add_flag("-q,--quiet", Variables->quietProcess, "Quiet process");
AppMain.add_flag("-V,--verbose", Variables->verboseMode,
"Detailed information is written on the screen while the "
"transaction is "
"being carried out");
AppMain.add_flag("-v,--version", Variables->viewVersion,
"Print version and exit");
if (argc < 2) { if (argc < 2) {
println("Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.", argv[0]); println(
return EXIT_FAILURE; "Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.",
} argv[0]);
return EXIT_FAILURE;
}
FuncManager.registerFunction(std::make_unique<backupFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<backupFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<flashFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<flashFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<partitionSizeFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<partitionSizeFunction>(),
FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain); AppMain);
FuncManager.registerFunction(std::make_unique<realPathFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<realLinkPathFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<realPathFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<typeFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<realLinkPathFunction>(),
FuncManager.registerFunction(std::make_unique<rebootFunction>(), AppMain); AppMain);
FuncManager.registerFunction(std::make_unique<typeFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<rebootFunction>(), AppMain);
CLI11_PARSE(AppMain, argc, argv); CLI11_PARSE(AppMain, argc, argv);
if (Variables->verboseMode) Helper::LoggingProperties::setPrinting(YES); if (Variables->verboseMode) Helper::LoggingProperties::setPrinting(YES);
if (Variables->viewVersion) { println("%s", getAppVersion().data()); return EXIT_SUCCESS; } if (Variables->viewVersion) {
if (!Variables->searchPath.empty()) (*Variables->PartMap)(Variables->searchPath); println("%s", getAppVersion().data());
return EXIT_SUCCESS;
}
if (!Variables->searchPath.empty())
(*Variables->PartMap)(Variables->searchPath);
if (!Variables->PartMap && Variables->searchPath.empty()) if (!Variables->PartMap && Variables->searchPath.empty())
throw Error("No default search entries were found. Specify a search directory with -S (--search-path)"); throw Error("No default search entries were found. Specify a search "
"directory with -S "
"(--search-path)");
if (!Helper::hasSuperUser()) throw Error("Partition Manager Tool is requires super-user privileges!\n"); if (!Helper::hasSuperUser())
throw Error(
"Partition Manager Tool is requires super-user privileges!\n");
return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE; return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE;
} catch (Helper::Error &error) { } catch (Helper::Error &error) {
// catch Helper::Error // catch Helper::Error
if (!Variables->quietProcess) fprintf(stderr, "%s%sERROR(S) OCCURRED:%s\n%s", RED, BOLD, STYLE_RESET, error.what()); if (!Variables->quietProcess)
return EXIT_FAILURE; fprintf(stderr, "%s%sERROR(S) OCCURRED:%s\n%s", RED, BOLD, STYLE_RESET,
} catch (CLI::Error &error) { error.what());
// catch CLI::Error return EXIT_FAILURE;
} catch (CLI::Error &error) {
// catch CLI::Error
fprintf(stderr, "%s: %s%sFLAG PARSE ERROR:%s %s\n", argv[0], RED, BOLD, STYLE_RESET, error.what()); fprintf(stderr, "%s: %s%sFLAG PARSE ERROR:%s %s\n", argv[0], RED, BOLD,
return EXIT_FAILURE; STYLE_RESET, error.what());
} // try-catch block end return EXIT_FAILURE;
} } // try-catch block end
}
void print(const char *format, ...) { void print(const char *format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
if (!Variables->quietProcess) vfprintf(stdout, format, args); if (!Variables->quietProcess) vfprintf(stdout, format, args);
va_end(args); va_end(args);
} }
void println(const char *format, ...) { void println(const char *format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
if (!Variables->quietProcess) { vfprintf(stdout, format, args); print("\n"); } if (!Variables->quietProcess) {
va_end(args); vfprintf(stdout, format, args);
} print("\n");
}
va_end(args);
}
std::string format(const char *format, ...) { std::string format(const char *format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
char str[1024]; char str[1024];
vsnprintf(str, sizeof(str), format, args); vsnprintf(str, sizeof(str), format, args);
va_end(args); va_end(args);
return str; return str;
} }
std::string getLibVersion() { std::string getLibVersion() { MKVERSION(PMT); }
MKVERSION(PMT);
}
std::string getAppVersion() { std::string getAppVersion() { MKVERSION(PMTE); }
MKVERSION(PMTE);
}
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -14,109 +14,151 @@
limitations under the License. limitations under the License.
*/ */
#include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#include <cerrno>
#include <chrono>
#include <cstdlib> #include <cstdlib>
#include <fcntl.h> #include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <future> #include <future>
#include <chrono>
#include <PartitionManager/PartitionManager.hpp>
#include <private/android_filesystem_config.h> #include <private/android_filesystem_config.h>
#include "functions.hpp" #include <unistd.h>
#define BFUN "backupFunction" #define BFUN "backupFunction"
namespace PartitionManager { namespace PartitionManager {
pair backupFunction::runAsync(const std::string &partitionName, const std::string &outputName, int bufferSize) { pair backupFunction::runAsync(const std::string &partitionName,
if (!Variables->PartMap->hasPartition(partitionName)) return { const std::string &outputName, int bufferSize) {
format("Couldn't find partition: %s", partitionName.data()), false if (!Variables->PartMap->hasPartition(partitionName))
}; return {format("Couldn't find partition: %s", partitionName.data()), false};
LOGN(BFUN, INFO) << "back upping " << partitionName << " as " << outputName << std::endl; LOGN(BFUN, INFO) << "back upping " << partitionName << " as " << outputName
<< std::endl;
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) if (Variables->forceProcess)
LOGN(BFUN, WARNING) << "Partition " << partitionName << LOGN(BFUN, WARNING)
" is exists but not logical. Ignoring (from --force, -f)." << std::endl; << "Partition " << partitionName
else return {format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false}; << " is exists but not logical. Ignoring (from --force, -f)."
} << std::endl;
else
return {
format("Used --logical (-l) flag but is not logical partition: %s",
partitionName.data()),
false};
}
if (Helper::fileIsExists(outputName) && !Variables->forceProcess) return { if (Helper::fileIsExists(outputName) && !Variables->forceProcess)
format("%s is exists. Remove it, or use --force (-f) flag.", outputName.data()), false return {format("%s is exists. Remove it, or use --force (-f) flag.",
}; outputName.data()),
false};
setupBufferSize(bufferSize, partitionName); setupBufferSize(bufferSize, partitionName);
LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName << "): " << bufferSize << std::endl; LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName
<< "): " << bufferSize << std::endl;
// Automatically close file descriptors and delete allocated memories (arrays) // Automatically close file descriptors and delete allocated memories (arrays)
Helper::garbageCollector collector; Helper::garbageCollector collector;
const int pfd = Helper::openAndAddToCloseList(Variables->PartMap->getRealPathOf(partitionName), collector, O_RDONLY); const int pfd = Helper::openAndAddToCloseList(
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false}; Variables->PartMap->getRealPathOf(partitionName), collector, O_RDONLY);
if (pfd < 0)
return {format("Can't open partition: %s: %s", partitionName.data(),
strerror(errno)),
false};
const int ffd = Helper::openAndAddToCloseList(outputName, collector, O_WRONLY | O_CREAT | O_TRUNC, 0644); const int ffd = Helper::openAndAddToCloseList(
if (ffd < 0) return {format("Can't create/open output file %s: %s", outputName.data(), strerror(errno)), false}; outputName, collector, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ffd < 0)
return {format("Can't create/open output file %s: %s", outputName.data(),
strerror(errno)),
false};
LOGN(BFUN, INFO) << "Writing partition " << partitionName << " to file: " << outputName << std::endl; LOGN(BFUN, INFO) << "Writing partition " << partitionName
auto *buffer = new char[bufferSize]; << " to file: " << outputName << std::endl;
collector.delAfterProgress(buffer); auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize); collector.delAfterProgress(buffer);
memset(buffer, 0x00, bufferSize);
ssize_t bytesRead; ssize_t bytesRead;
while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) { while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) {
if (const ssize_t bytesWritten = write(ffd, buffer, bytesRead); bytesWritten != bytesRead) if (const ssize_t bytesWritten = write(ffd, buffer, bytesRead);
return {format("Can't write partition to output file %s: %s", outputName.data(), strerror(errno)), false}; bytesWritten != bytesRead)
} return {format("Can't write partition to output file %s: %s",
outputName.data(), strerror(errno)),
false};
}
if (!Helper::changeOwner(outputName, AID_EVERYBODY, AID_EVERYBODY)) if (!Helper::changeOwner(outputName, AID_EVERYBODY, AID_EVERYBODY))
LOGN(BFUN, WARNING) << "Failed to change owner of output file: " << outputName << ". Access problems maybe occur in non-root mode" << std::endl; LOGN(BFUN, WARNING) << "Failed to change owner of output file: "
if (!Helper::changeMode(outputName, 0660)) << outputName
LOGN(BFUN, WARNING) << "Failed to change mode of output file as 660: " << outputName << ". Access problems maybe occur in non-root mode" << std::endl; << ". Access problems maybe occur in non-root mode"
<< std::endl;
if (!Helper::changeMode(outputName, 0660))
LOGN(BFUN, WARNING) << "Failed to change mode of output file as 660: "
<< outputName
<< ". Access problems maybe occur in non-root mode"
<< std::endl;
return {format("%s partition successfully back upped to %s", partitionName.data(), outputName.data()), true}; return {format("%s partition successfully back upped to %s",
} partitionName.data(), outputName.data()),
true};
}
bool backupFunction::init(CLI::App &_app) { bool backupFunction::init(CLI::App &_app) {
LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl; LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl;
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)"); cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required(); cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")
cmd->add_option("output(s)", rawOutputNames, "File name(s) (or path(s)) to save the partition image(s)"); ->required();
cmd->add_option("-O,--output-directory", outputDirectory, "Directory to save the partition image(s)")->check(CLI::ExistingDirectory); cmd->add_option("output(s)", rawOutputNames,
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading partition(s) and writing to file(s)"); "File name(s) (or path(s)) to save the partition image(s)");
cmd->add_option("-O,--output-directory", outputDirectory,
"Directory to save the partition image(s)")
->check(CLI::ExistingDirectory);
cmd->add_option(
"-b,--buffer-size", bufferSize,
"Buffer size for reading partition(s) and writing to file(s)");
return true; return true;
} }
bool backupFunction::run() { bool backupFunction::run() {
processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames, ',', true); processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames,
if (!outputNames.empty() && partitions.size() != outputNames.size()) ',', true);
throw CLI::ValidationError("You must provide an output name(s) as long as the partition name(s)"); if (!outputNames.empty() && partitions.size() != outputNames.size())
throw CLI::ValidationError(
"You must provide an output name(s) as long as the partition name(s)");
std::vector<std::future<pair>> futures; std::vector<std::future<pair>> futures;
for (size_t i = 0; i < partitions.size(); i++) { for (size_t i = 0; i < partitions.size(); i++) {
std::string partitionName = partitions[i]; std::string partitionName = partitions[i];
std::string outputName = outputNames.empty() ? partitionName + ".img" : outputNames[i]; std::string outputName =
if (!outputDirectory.empty()) outputName.insert(0, outputDirectory + '/'); outputNames.empty() ? partitionName + ".img" : outputNames[i];
if (!outputDirectory.empty()) outputName.insert(0, outputDirectory + '/');
futures.push_back(std::async(std::launch::async, runAsync, partitionName, outputName, bufferSize)); futures.push_back(std::async(std::launch::async, runAsync, partitionName,
LOGN(BFUN, INFO) << "Created thread backup upping " << partitionName << std::endl; outputName, bufferSize));
} LOGN(BFUN, INFO) << "Created thread backup upping " << partitionName
<< std::endl;
}
std::string end; std::string end;
bool endResult = true; bool endResult = true;
for (auto &future: futures) { for (auto &future : futures) {
auto [fst, snd] = future.get(); auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; } if (!snd) {
else println("%s", fst.c_str()); end += fst + '\n';
} endResult = false;
} else println("%s", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str()); if (!endResult) throw Error("%s", end.c_str());
LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl; LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult; return endResult;
} }
bool backupFunction::isUsed() const { return cmd->parsed(); } bool backupFunction::isUsed() const { return cmd->parsed(); }
const char *backupFunction::name() const { return BFUN; } const char *backupFunction::name() const { return BFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -14,91 +14,116 @@ Copyright 2025 Yağız Zengin
limitations under the License. limitations under the License.
*/ */
#include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <fcntl.h> #include <fcntl.h>
#include <cerrno>
#include <future> #include <future>
#include <unistd.h> #include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define EFUN "eraseFunction" #define EFUN "eraseFunction"
namespace PartitionManager { namespace PartitionManager {
pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) { pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
if (!Variables->PartMap->hasPartition(partitionName)) return { if (!Variables->PartMap->hasPartition(partitionName))
format("Couldn't find partition: %s", partitionName.data()), false return {format("Couldn't find partition: %s", partitionName.data()), false};
};
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) if (Variables->forceProcess)
LOGN(EFUN, WARNING) << "Partition " << partitionName << LOGN(EFUN, WARNING)
" is exists but not logical. Ignoring (from --force, -f)." << std::endl; << "Partition " << partitionName
else return {format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false}; << " is exists but not logical. Ignoring (from --force, -f)."
} << std::endl;
else
return {
format("Used --logical (-l) flag but is not logical partition: %s",
partitionName.data()),
false};
}
setupBufferSize(bufferSize, partitionName); setupBufferSize(bufferSize, partitionName);
LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize; LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize;
// Automatically close file descriptors and delete allocated memories (arrays) // Automatically close file descriptors and delete allocated memories (arrays)
Helper::garbageCollector collector; Helper::garbageCollector collector;
const int pfd = Helper::openAndAddToCloseList(Variables->PartMap->getRealPathOf(partitionName), collector, O_WRONLY); const int pfd = Helper::openAndAddToCloseList(
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false}; Variables->PartMap->getRealPathOf(partitionName), collector, O_WRONLY);
if (pfd < 0)
return {format("Can't open partition: %s: %s", partitionName.data(),
strerror(errno)),
false};
if (!Variables->forceProcess) Helper::confirmPropt( if (!Variables->forceProcess)
"Are you sure you want to continue? This could render your device unusable! Do not continue if you do not know what you are doing!"); Helper::confirmPropt(
"Are you sure you want to continue? This could render your device "
"unusable! Do not continue if you "
"do not know what you are doing!");
LOGN(EFUN, INFO) << "Writing zero bytes to partition: " << partitionName << std::endl; LOGN(EFUN, INFO) << "Writing zero bytes to partition: " << partitionName
auto *buffer = new char[bufferSize]; << std::endl;
collector.delAfterProgress(buffer); auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize); collector.delAfterProgress(buffer);
memset(buffer, 0x00, bufferSize);
ssize_t bytesWritten = 0; ssize_t bytesWritten = 0;
const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName); const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName);
while (bytesWritten < partitionSize) { while (bytesWritten < partitionSize) {
size_t toWrite = sizeof(buffer); size_t toWrite = sizeof(buffer);
if (partitionSize - bytesWritten < sizeof(buffer)) toWrite = partitionSize - bytesWritten; if (partitionSize - bytesWritten < sizeof(buffer))
toWrite = partitionSize - bytesWritten;
if (const ssize_t result = write(pfd, buffer, toWrite); result == -1) if (const ssize_t result = write(pfd, buffer, toWrite); result == -1)
return {format("Can't write zero bytes to partition: %s: %s", partitionName.data(), strerror(errno)), false}; return {format("Can't write zero bytes to partition: %s: %s",
else bytesWritten += result; partitionName.data(), strerror(errno)),
} false};
else bytesWritten += result;
}
return {format("Successfully wrote zero bytes to the %s partition\n", partitionName.data()), true}; return {format("Successfully wrote zero bytes to the %s partition\n",
} partitionName.data()),
true};
}
bool eraseFunction::init(CLI::App &_app) { bool eraseFunction::init(CLI::App &_app) {
LOGN(EFUN, INFO) << "Initializing variables of erase function." << std::endl; LOGN(EFUN, INFO) << "Initializing variables of erase function." << std::endl;
cmd = _app.add_subcommand("erase", "Writes zero bytes to partition(s)"); cmd = _app.add_subcommand("erase", "Writes zero bytes to partition(s)");
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required()->delimiter(','); cmd->add_option("partition(s)", partitions, "Partition name(s)")
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for writing zero bytes to partition(s)"); ->required()
return true; ->delimiter(',');
} cmd->add_option("-b,--buffer-size", bufferSize,
"Buffer size for writing zero bytes to partition(s)");
return true;
}
bool eraseFunction::run() { bool eraseFunction::run() {
std::vector<std::future<pair>> futures; std::vector<std::future<pair>> futures;
for (const auto &partitionName: partitions) { for (const auto &partitionName : partitions) {
futures.push_back(std::async(std::launch::async, runAsync, partitionName, bufferSize)); futures.push_back(
LOGN(EFUN, INFO) << "Created thread for writing zero bytes to " << partitionName << std::endl; std::async(std::launch::async, runAsync, partitionName, bufferSize));
} LOGN(EFUN, INFO) << "Created thread for writing zero bytes to "
<< partitionName << std::endl;
}
std::string end; std::string end;
bool endResult = true; bool endResult = true;
for (auto &future: futures) { for (auto &future : futures) {
auto [fst, snd] = future.get(); auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; } if (!snd) {
else println("%s", fst.c_str()); end += fst + '\n';
} endResult = false;
} else println("%s", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str()); if (!endResult) throw Error("%s", end.c_str());
LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl; LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult; return endResult;
} }
bool eraseFunction::isUsed() const { return cmd->parsed(); } bool eraseFunction::isUsed() const { return cmd->parsed(); }
const char *eraseFunction::name() const { return EFUN; } const char *eraseFunction::name() const { return EFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -14,102 +14,135 @@ Copyright 2025 Yağız Zengin
limitations under the License. limitations under the License.
*/ */
#include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <fcntl.h> #include <fcntl.h>
#include <cerrno>
#include <future> #include <future>
#include <unistd.h> #include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define FFUN "flashFunction" #define FFUN "flashFunction"
namespace PartitionManager { namespace PartitionManager {
pair flashFunction::runAsync(const std::string &partitionName, const std::string &imageName, int bufferSize) { pair flashFunction::runAsync(const std::string &partitionName,
if (!Helper::fileIsExists(imageName)) return {format("Couldn't find image file: %s", imageName.data()), false}; const std::string &imageName, int bufferSize) {
if (!Variables->PartMap->hasPartition(partitionName)) return {format("Couldn't find partition: %s", partitionName.data()), false}; if (!Helper::fileIsExists(imageName))
if (Helper::fileSize(imageName) > Variables->PartMap->sizeOf(partitionName)) return {format("Couldn't find image file: %s", imageName.data()), false};
return {format("%s is larger than %s partition size!", imageName.data(), partitionName.data()), false}; if (!Variables->PartMap->hasPartition(partitionName))
return {format("Couldn't find partition: %s", partitionName.data()), false};
if (Helper::fileSize(imageName) > Variables->PartMap->sizeOf(partitionName))
return {format("%s is larger than %s partition size!", imageName.data(),
partitionName.data()),
false};
LOGN(FFUN, INFO) << "flashing " << imageName << " to " << partitionName << std::endl; LOGN(FFUN, INFO) << "flashing " << imageName << " to " << partitionName
<< std::endl;
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) if (Variables->forceProcess)
LOGN(FFUN, WARNING) << "Partition " << partitionName << LOGN(FFUN, WARNING)
" is exists but not logical. Ignoring (from --force, -f)." << std::endl; << "Partition " << partitionName
else return { << " is exists but not logical. Ignoring (from --force, -f)."
format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false << std::endl;
}; else
} return {
format("Used --logical (-l) flag but is not logical partition: %s",
partitionName.data()),
false};
}
setupBufferSize(bufferSize, imageName); setupBufferSize(bufferSize, imageName);
LOGN(FFUN, INFO) << "Using buffer size: " << bufferSize; LOGN(FFUN, INFO) << "Using buffer size: " << bufferSize;
// Automatically close file descriptors and delete allocated memories (arrays) // Automatically close file descriptors and delete allocated memories (arrays)
Helper::garbageCollector collector; Helper::garbageCollector collector;
const int ffd = Helper::openAndAddToCloseList(imageName, collector, O_RDONLY); const int ffd = Helper::openAndAddToCloseList(imageName, collector, O_RDONLY);
if (ffd < 0) return {format("Can't open image file %s: %s", imageName.data(), strerror(errno)), false}; if (ffd < 0)
return {format("Can't open image file %s: %s", imageName.data(),
strerror(errno)),
false};
const int pfd = Helper::openAndAddToCloseList(Variables->PartMap->getRealPathOf(partitionName), collector, O_RDWR | O_TRUNC); const int pfd = Helper::openAndAddToCloseList(
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false}; Variables->PartMap->getRealPathOf(partitionName), collector,
O_RDWR | O_TRUNC);
if (pfd < 0)
return {format("Can't open partition: %s: %s", partitionName.data(),
strerror(errno)),
false};
LOGN(FFUN, INFO) << "Writing image " << imageName << " to partition: " << partitionName << std::endl; LOGN(FFUN, INFO) << "Writing image " << imageName
auto *buffer = new char[bufferSize]; << " to partition: " << partitionName << std::endl;
collector.delAfterProgress(buffer); auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize); collector.delAfterProgress(buffer);
memset(buffer, 0x00, bufferSize);
ssize_t bytesRead; ssize_t bytesRead;
while ((bytesRead = read(ffd, buffer, bufferSize)) > 0) { while ((bytesRead = read(ffd, buffer, bufferSize)) > 0) {
if (const ssize_t bytesWritten = write(pfd, buffer, bytesRead); bytesWritten != bytesRead) if (const ssize_t bytesWritten = write(pfd, buffer, bytesRead);
return {format("Can't write partition to output file %s: %s", imageName.data(), strerror(errno)), false}; bytesWritten != bytesRead)
} return {format("Can't write partition to output file %s: %s",
imageName.data(), strerror(errno)),
false};
}
return {format("%s is successfully wrote to %s partition", imageName.data(), partitionName.data()), true}; return {format("%s is successfully wrote to %s partition", imageName.data(),
} partitionName.data()),
true};
}
bool flashFunction::init(CLI::App &_app) { bool flashFunction::init(CLI::App &_app) {
LOGN(FFUN, INFO) << "Initializing variables of flash function." << std::endl; LOGN(FFUN, INFO) << "Initializing variables of flash function." << std::endl;
cmd = _app.add_subcommand("flash", "Flash image(s) to partition(s)"); cmd = _app.add_subcommand("flash", "Flash image(s) to partition(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required(); cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")
cmd->add_option("imageFile(s)", rawImageNames, "Name(s) of image file(s)")->required(); ->required();
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading image(s) and writing to partition(s)"); cmd->add_option("imageFile(s)", rawImageNames, "Name(s) of image file(s)")
cmd->add_option("-I,--image-directory", imageDirectory, "Directory to find image(s) and flash to partition(s)"); ->required();
cmd->add_option(
"-b,--buffer-size", bufferSize,
"Buffer size for reading image(s) and writing to partition(s)");
cmd->add_option("-I,--image-directory", imageDirectory,
"Directory to find image(s) and flash to partition(s)");
return true; return true;
} }
bool flashFunction::run() { bool flashFunction::run() {
processCommandLine(partitions, imageNames, rawPartitions, rawImageNames, ',', true); processCommandLine(partitions, imageNames, rawPartitions, rawImageNames, ',',
if (partitions.size() != imageNames.size()) true);
throw CLI::ValidationError("You must provide an image file(s) as long as the partition name(s)"); if (partitions.size() != imageNames.size())
throw CLI::ValidationError(
"You must provide an image file(s) as long as the partition name(s)");
std::vector<std::future<pair>> futures; std::vector<std::future<pair>> futures;
for (size_t i = 0; i < partitions.size(); i++) { for (size_t i = 0; i < partitions.size(); i++) {
std::string imageName = imageNames[i]; std::string imageName = imageNames[i];
if (!imageDirectory.empty()) imageName.insert(0, imageDirectory + '/'); if (!imageDirectory.empty()) imageName.insert(0, imageDirectory + '/');
futures.push_back(std::async(std::launch::async, runAsync, partitions[i], imageName, bufferSize)); futures.push_back(std::async(std::launch::async, runAsync, partitions[i],
LOGN(FFUN, INFO) << "Created thread for flashing image to " << partitions[i] << std::endl; imageName, bufferSize));
} LOGN(FFUN, INFO) << "Created thread for flashing image to " << partitions[i]
<< std::endl;
}
std::string end; std::string end;
bool endResult = true; bool endResult = true;
for (auto &future: futures) { for (auto &future : futures) {
auto [fst, snd] = future.get(); auto [fst, snd] = future.get();
if (!snd) { if (!snd) {
end += fst + '\n'; end += fst + '\n';
endResult = false; endResult = false;
} else println("%s", fst.c_str()); } else println("%s", fst.c_str());
} }
if (!endResult) throw Error("%s", end.c_str()); if (!endResult) throw Error("%s", end.c_str());
LOGN(FFUN, INFO) << "Operation successfully completed." << std::endl; LOGN(FFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult; return endResult;
} }
bool flashFunction::isUsed() const { return cmd->parsed(); } bool flashFunction::isUsed() const { return cmd->parsed(); }
const char *flashFunction::name() const { return FFUN; } const char *flashFunction::name() const { return FFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -14,77 +14,89 @@ Copyright 2025 Yağız Zengin
limitations under the License. limitations under the License.
*/ */
#include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <fcntl.h> #include <fcntl.h>
#include <cerrno>
#include <unistd.h> #include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define IFUN "infoFunction" #define IFUN "infoFunction"
namespace PartitionManager { namespace PartitionManager {
bool infoFunction::init(CLI::App &_app) { bool infoFunction::init(CLI::App &_app) {
LOGN(IFUN, INFO) << "Initializing variables of info printer function." << std::endl; LOGN(IFUN, INFO) << "Initializing variables of info printer function."
cmd = _app.add_subcommand("info", "Tell info(s) of input partition list")->footer( << std::endl;
"Use get-all or getvar-all as partition name for getting info's of all partitions."); cmd = _app.add_subcommand("info", "Tell info(s) of input partition list")
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(','); ->footer("Use get-all or getvar-all as partition name for getting "
cmd->add_flag("-J,--json", jsonFormat, "info's of all "
"Print info(s) as JSON body. The body of each partition will be written separately"); "partitions.");
cmd->add_option("--json-partition-name", jNamePartition, "Speficy partition name element for JSON body"); cmd->add_option("partition(s)", partitions, "Partition name(s).")
cmd->add_option("--json-size-name", jNameSize, "Speficy size element name for JSON body"); ->required()
cmd->add_option("--json-logical-name", jNameLogical, "Speficy logical element name for JSON body"); ->delimiter(',');
return true; cmd->add_flag("-J,--json", jsonFormat,
} "Print info(s) as JSON body. The body of each partition will "
"be written separately");
cmd->add_option("--json-partition-name", jNamePartition,
"Speficy partition name element for JSON body");
cmd->add_option("--json-size-name", jNameSize,
"Speficy size element name for JSON body");
cmd->add_option("--json-logical-name", jNameLogical,
"Speficy logical element name for JSON body");
return true;
}
bool infoFunction::run() { bool infoFunction::run() {
if (partitions.back() == "get-all" || partitions.back() == "getvar-all") { if (partitions.back() == "get-all" || partitions.back() == "getvar-all") {
partitions.clear(); partitions.clear();
const auto parts = Variables->PartMap->getPartitionList(); const auto parts = Variables->PartMap->getPartitionList();
if (!parts) throw Error("Cannot get list of all partitions! See logs for more information (%s)", if (!parts)
Helper::LoggingProperties::FILE.data()); throw Error("Cannot get list of all partitions! See logs for more "
"information (%s)",
Helper::LoggingProperties::FILE.data());
for (const auto &name: *parts) partitions.push_back(name); for (const auto &name : *parts)
} partitions.push_back(name);
}
for (const auto &partition: partitions) { for (const auto &partition : partitions) {
if (!Variables->PartMap->hasPartition(partition)) if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data()); throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess) if (Variables->forceProcess)
LOGN(IFUN, WARNING) << "Partition " << partition << LOGN(IFUN, WARNING)
" is exists but not logical. Ignoring (from --force, -f)." << std::endl; << "Partition " << partition
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); << " is exists but not logical. Ignoring (from --force, -f)."
} << std::endl;
else
throw Error("Used --logical (-l) flag but is not logical partition: %s",
partition.data());
}
if (jsonFormat) if (jsonFormat)
#ifdef __LP64__ #ifdef __LP64__
println("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}", println("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}",
#else #else
println("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}", println("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}",
#endif #endif
jNamePartition.data(), jNamePartition.data(), partition.data(), jNameSize.data(),
partition.data(), Variables->PartMap->sizeOf(partition), jNameLogical.data(),
jNameSize.data(), Variables->PartMap->isLogical(partition) ? "true" : "false");
Variables->PartMap->sizeOf(partition), else
jNameLogical.data(),
Variables->PartMap->isLogical(partition) ? "true" : "false");
else
#ifdef __LP64__ #ifdef __LP64__
println("partition=%s size=%lu isLogical=%s", println("partition=%s size=%lu isLogical=%s",
#else #else
println("partition=%s size=%llu isLogical=%s", println("partition=%s size=%llu isLogical=%s",
#endif #endif
partition.data(), partition.data(), Variables->PartMap->sizeOf(partition),
Variables->PartMap->sizeOf(partition), Variables->PartMap->isLogical(partition) ? "true" : "false");
Variables->PartMap->isLogical(partition) ? "true" : "false"); }
}
return true; return true;
} }
bool infoFunction::isUsed() const { return cmd->parsed(); } bool infoFunction::isUsed() const { return cmd->parsed(); }
const char *infoFunction::name() const { return IFUN; }; const char *infoFunction::name() const { return IFUN; };
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -14,59 +14,77 @@ Copyright 2025 Yağız Zengin
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#define SFUN "partitionSizeFunction" #define SFUN "partitionSizeFunction"
std::string convertTo(const uint64_t size, const std::string &multiple) { std::string convertTo(const uint64_t size, const std::string &multiple) {
if (multiple == "KB") return std::to_string(TO_KB(size)); if (multiple == "KB") return std::to_string(TO_KB(size));
if (multiple == "MB") return std::to_string(TO_MB(size)); if (multiple == "MB") return std::to_string(TO_MB(size));
if (multiple == "GB") return std::to_string(TO_GB(size)); if (multiple == "GB") return std::to_string(TO_GB(size));
return std::to_string(size); return std::to_string(size);
} }
namespace PartitionManager { namespace PartitionManager {
bool partitionSizeFunction::init(CLI::App &_app) { bool partitionSizeFunction::init(CLI::App &_app) {
LOGN(SFUN, INFO) << "Initializing variables of partition size getter function." << std::endl; LOGN(SFUN, INFO)
cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list"); << "Initializing variables of partition size getter function."
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(','); << std::endl;
cmd->add_flag("--as-byte", asByte, "Tell input size of partition list as byte."); cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list");
cmd->add_flag("--as-kilobyte", asKiloBytes, "Tell input size of partition list as kilobyte."); cmd->add_option("partition(s)", partitions, "Partition name(s).")
cmd->add_flag("--as-megabyte", asMega, "Tell input size of partition list as megabyte."); ->required()
cmd->add_flag("--as-gigabyte", asGiga, "Tell input size of partition list as gigabyte."); ->delimiter(',');
cmd->add_flag("--only-size", onlySize, "Tell input size of partition list as not printing multiple and partition name."); cmd->add_flag("--as-byte", asByte,
return true; "Tell input size of partition list as byte.");
cmd->add_flag("--as-kilobyte", asKiloBytes,
"Tell input size of partition list as kilobyte.");
cmd->add_flag("--as-megabyte", asMega,
"Tell input size of partition list as megabyte.");
cmd->add_flag("--as-gigabyte", asGiga,
"Tell input size of partition list as gigabyte.");
cmd->add_flag("--only-size", onlySize,
"Tell input size of partition list as not printing multiple "
"and partition name.");
return true;
}
bool partitionSizeFunction::run() {
for (const auto &partition : partitions) {
if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess)
LOGN(SFUN, WARNING)
<< "Partition " << partition
<< " is exists but not logical. Ignoring (from --force, -f)."
<< std::endl;
else
throw Error("Used --logical (-l) flag but is not logical partition: %s",
partition.data());
} }
bool partitionSizeFunction::run() { std::string multiple = "MB";
for (const auto &partition: partitions) { if (asByte) multiple = "B";
if (!Variables->PartMap->hasPartition(partition)) if (asKiloBytes) multiple = "KB";
throw Error("Couldn't find partition: %s", partition.data()); if (asMega) multiple = "MB";
if (asGiga) multiple = "GB";
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) { if (onlySize)
if (Variables->forceProcess) println(
LOGN(SFUN, WARNING) << "Partition " << partition << "%s",
" is exists but not logical. Ignoring (from --force, -f)." << std::endl; convertTo(Variables->PartMap->sizeOf(partition), multiple).data());
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); else
} println("%s: %s%s", partition.data(),
convertTo(Variables->PartMap->sizeOf(partition), multiple).data(),
multiple.data());
}
std::string multiple = "MB"; return true;
if (asByte) multiple = "B"; }
if (asKiloBytes) multiple = "KB";
if (asMega) multiple = "MB";
if (asGiga) multiple = "GB";
if (onlySize) bool partitionSizeFunction::isUsed() const { return cmd->parsed(); }
println("%s", convertTo(Variables->PartMap->sizeOf(partition), multiple).data());
else
println("%s: %s%s", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(), multiple.data());
}
return true; const char *partitionSizeFunction::name() const { return SFUN; }
}
bool partitionSizeFunction::isUsed() const { return cmd->parsed(); }
const char *partitionSizeFunction::name() const { return SFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -1,11 +1,11 @@
/* /*
Copyright 2025 Yağız Zengin Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,38 +14,46 @@
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#define RLPFUN "realPathFunction" #define RLPFUN "realPathFunction"
namespace PartitionManager { namespace PartitionManager {
bool realLinkPathFunction::init(CLI::App &_app) { bool realLinkPathFunction::init(CLI::App &_app) {
LOGN(RLPFUN, INFO) << "Initializing variables of real link path function." << std::endl; LOGN(RLPFUN, INFO) << "Initializing variables of real link path function."
cmd = _app.add_subcommand("real-linkpath", "Tell real link paths of partition(s)"); << std::endl;
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required()->delimiter(','); cmd = _app.add_subcommand("real-linkpath",
return true; "Tell real link paths of partition(s)");
} cmd->add_option("partition(s)", partitions, "Partition name(s)")
->required()
->delimiter(',');
return true;
}
bool realLinkPathFunction::run() { bool realLinkPathFunction::run() {
for (const auto &partition: partitions) { for (const auto &partition : partitions) {
if (!Variables->PartMap->hasPartition(partition)) if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data()); throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess) if (Variables->forceProcess)
LOGN(RLPFUN, WARNING) << "Partition " << partition << LOGN(RLPFUN, WARNING)
" is exists but not logical. Ignoring (from --force, -f)." << std::endl; << "Partition " << partition
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); << " is exists but not logical. Ignoring (from --force, -f)."
} << std::endl;
else
throw Error("Used --logical (-l) flag but is not logical partition: %s",
partition.data());
}
println("%s", Variables->PartMap->getRealPathOf(partition).data()); println("%s", Variables->PartMap->getRealPathOf(partition).data());
} }
return true; return true;
} }
bool realLinkPathFunction::isUsed() const { return cmd->parsed(); } bool realLinkPathFunction::isUsed() const { return cmd->parsed(); }
const char *realLinkPathFunction::name() const { return RLPFUN; } const char *realLinkPathFunction::name() const { return RLPFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -1,11 +1,11 @@
/* /*
Copyright 2025 Yağız Zengin Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,38 +14,45 @@
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#define RPFUN "realPathFunction" #define RPFUN "realPathFunction"
namespace PartitionManager { namespace PartitionManager {
bool realPathFunction::init(CLI::App &_app) { bool realPathFunction::init(CLI::App &_app) {
LOGN(RPFUN, INFO) << "Initializing variables of real path function." << std::endl; LOGN(RPFUN, INFO) << "Initializing variables of real path function."
cmd = _app.add_subcommand("real-path", "Tell real paths of partition(s)"); << std::endl;
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required()->delimiter(','); cmd = _app.add_subcommand("real-path", "Tell real paths of partition(s)");
return true; cmd->add_option("partition(s)", partitions, "Partition name(s)")
} ->required()
->delimiter(',');
return true;
}
bool realPathFunction::run() { bool realPathFunction::run() {
for (const auto &partition: partitions) { for (const auto &partition : partitions) {
if (!Variables->PartMap->hasPartition(partition)) if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data()); throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess) if (Variables->forceProcess)
LOGN(RPFUN, WARNING) << "Partition " << partition << LOGN(RPFUN, WARNING)
" is exists but not logical. Ignoring (from --force, -f)." << std::endl; << "Partition " << partition
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); << " is exists but not logical. Ignoring (from --force, -f)."
} << std::endl;
else
throw Error("Used --logical (-l) flag but is not logical partition: %s",
partition.data());
}
println("%s", Variables->PartMap->getRealPathOf(partition).data()); println("%s", Variables->PartMap->getRealPathOf(partition).data());
} }
return true; return true;
} }
bool realPathFunction::isUsed() const { return cmd->parsed(); } bool realPathFunction::isUsed() const { return cmd->parsed(); }
const char *realPathFunction::name() const { return RPFUN; } const char *realPathFunction::name() const { return RPFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -5,7 +5,7 @@ Copyright 2025 Yağız Zengin
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,29 +14,32 @@ Copyright 2025 Yağız Zengin
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#define RFUN "rebootFunction" #define RFUN "rebootFunction"
namespace PartitionManager { namespace PartitionManager {
bool rebootFunction::init(CLI::App &_app) { bool rebootFunction::init(CLI::App &_app) {
LOGN(RFUN, INFO) << "Initializing variables of reboot function." << std::endl; LOGN(RFUN, INFO) << "Initializing variables of reboot function." << std::endl;
cmd = _app.add_subcommand("reboot", "Reboots device"); cmd = _app.add_subcommand("reboot", "Reboots device");
cmd->add_option("rebootTarget", rebootTarget, "Reboot target (default: normal)"); cmd->add_option("rebootTarget", rebootTarget,
return true; "Reboot target (default: normal)");
} return true;
}
bool rebootFunction::run() { bool rebootFunction::run() {
LOGN(RFUN, INFO) << "Rebooting device!!! (custom reboot target: " << (rebootTarget.empty() ? "none" : rebootTarget) << std::endl; LOGN(RFUN, INFO) << "Rebooting device!!! (custom reboot target: "
<< (rebootTarget.empty() ? "none" : rebootTarget)
<< std::endl;
if (Helper::reboot(rebootTarget)) println("Reboot command was sent"); if (Helper::reboot(rebootTarget)) println("Reboot command was sent");
else throw Error("Cannot reboot device"); else throw Error("Cannot reboot device");
return true; return true;
} }
bool rebootFunction::isUsed() const { return cmd->parsed(); } bool rebootFunction::isUsed() const { return cmd->parsed(); }
const char* rebootFunction::name() const { return RFUN; } const char *rebootFunction::name() const { return RFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -5,7 +5,7 @@
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,49 +14,65 @@
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#define TFUN "typeFunction" #define TFUN "typeFunction"
namespace PartitionManager { namespace PartitionManager {
bool typeFunction::init(CLI::App &_app) { bool typeFunction::init(CLI::App &_app) {
LOGN(TFUN, INFO) << "Initializing variables of type function." << std::endl; LOGN(TFUN, INFO) << "Initializing variables of type function." << std::endl;
cmd = _app.add_subcommand("type", "Get type of the partition(s) or image(s)"); cmd = _app.add_subcommand("type", "Get type of the partition(s) or image(s)");
cmd->add_option("content(s)", contents, "Content(s)")->required()->delimiter(','); cmd->add_option("content(s)", contents, "Content(s)")
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for max seek depth"); ->required()
cmd->add_flag("--only-check-android-magics", onlyCheckAndroidMagics, "Only check Android magic values."); ->delimiter(',');
cmd->add_flag("--only-check-filesystem-magics", onlyCheckFileSystemMagics, "Only check filesystem magic values."); cmd->add_option("-b,--buffer-size", bufferSize,
return true; "Buffer size for max seek depth");
} cmd->add_flag("--only-check-android-magics", onlyCheckAndroidMagics,
"Only check Android magic values.");
cmd->add_flag("--only-check-filesystem-magics", onlyCheckFileSystemMagics,
"Only check filesystem magic values.");
return true;
}
bool typeFunction::run() { bool typeFunction::run() {
std::unordered_map<uint64_t, std::string> magics; std::unordered_map<uint64_t, std::string> magics;
if (onlyCheckAndroidMagics) magics.merge(PartitionMap::Extras::AndroidMagicMap); if (onlyCheckAndroidMagics)
else if (onlyCheckFileSystemMagics) magics.merge(PartitionMap::Extras::FileSystemMagicMap); magics.merge(PartitionMap::Extras::AndroidMagicMap);
else magics.merge(PartitionMap::Extras::MagicMap); else if (onlyCheckFileSystemMagics)
magics.merge(PartitionMap::Extras::FileSystemMagicMap);
else magics.merge(PartitionMap::Extras::MagicMap);
for (const auto& content : contents) { for (const auto &content : contents) {
if (!Variables->PartMap->hasPartition(content) && !Helper::fileIsExists(content)) if (!Variables->PartMap->hasPartition(content) &&
throw Error("Couldn't find partition or image file: %s\n", content.data()); !Helper::fileIsExists(content))
throw Error("Couldn't find partition or image file: %s\n",
content.data());
bool found = false; bool found = false;
for (const auto& [magic, name] : magics) { for (const auto &[magic, name] : magics) {
if (PartitionMap::Extras::hasMagic(magic, bufferSize, Helper::fileIsExists(content) ? content : Variables->PartMap->getRealPathOf(content))) { if (PartitionMap::Extras::hasMagic(
println("%s contains %s magic (%s)", content.data(), name.data(), PartitionMap::Extras::formatMagic(magic).data()); magic, bufferSize,
found = true; Helper::fileIsExists(content)
break; ? content
} : Variables->PartMap->getRealPathOf(content))) {
} println("%s contains %s magic (%s)", content.data(), name.data(),
PartitionMap::Extras::formatMagic(magic).data());
found = true;
break;
}
}
if (!found) throw Error("Couldn't determine type of %s%s\n", content.data(), content == "userdata" ? " (encrypted file system?)" : ""); if (!found)
} throw Error("Couldn't determine type of %s%s\n", content.data(),
content == "userdata" ? " (encrypted file system?)" : "");
}
return true; return true;
} }
bool typeFunction::isUsed() const { return cmd->parsed(); } bool typeFunction::isUsed() const { return cmd->parsed(); }
const char* typeFunction::name() const { return TFUN; } const char *typeFunction::name() const { return TFUN; }
} // namespace PartitionManager } // namespace PartitionManager

222
src/functions/functions.hpp Executable file → Normal file
View File

@@ -22,151 +22,155 @@
#include <vector> #include <vector>
namespace PartitionManager { namespace PartitionManager {
using pair = std::pair<std::string, bool>; using pair = std::pair<std::string, bool>;
// Back-up function // Back-up function
class backupFunction final : public FunctionBase { class backupFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions, outputNames; std::vector<std::string> partitions, outputNames;
std::string rawPartitions, rawOutputNames, outputDirectory; std::string rawPartitions, rawOutputNames, outputDirectory;
int bufferSize = 4096; int bufferSize = 4096;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
static pair runAsync(const std::string &partitionName, const std::string &outputName, int bufferSize); static pair runAsync(const std::string &partitionName,
const std::string &outputName, int bufferSize);
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
// Image flasher function // Image flasher function
class flashFunction final : public FunctionBase { class flashFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions, imageNames; std::vector<std::string> partitions, imageNames;
std::string rawPartitions, rawImageNames, imageDirectory; std::string rawPartitions, rawImageNames, imageDirectory;
int bufferSize = 4096; int bufferSize = 4096;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
static pair runAsync(const std::string &partitionName, const std::string &imageName, int bufferSize); static pair runAsync(const std::string &partitionName,
const std::string &imageName, int bufferSize);
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
// Eraser function (writes zero bytes to partition) // Eraser function (writes zero bytes to partition)
class eraseFunction final : public FunctionBase { class eraseFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
int bufferSize = 4096; int bufferSize = 4096;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
static pair runAsync(const std::string &partitionName, int bufferSize); static pair runAsync(const std::string &partitionName, int bufferSize);
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
// Partition size getter function // Partition size getter function
class partitionSizeFunction final : public FunctionBase { class partitionSizeFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
bool onlySize = false, asByte = false, asKiloBytes = false, asMega = false, asGiga = false; bool onlySize = false, asByte = false, asKiloBytes = false, asMega = false,
asGiga = false;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
// Partition info getter function // Partition info getter function
class infoFunction final : public FunctionBase { class infoFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
std::string jNamePartition = "name", jNameSize = "size", jNameLogical = "isLogical"; std::string jNamePartition = "name", jNameSize = "size",
bool jsonFormat = false; jNameLogical = "isLogical";
bool jsonFormat = false;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
class realPathFunction final : public FunctionBase { class realPathFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
class realLinkPathFunction final : public FunctionBase { class realLinkPathFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
class typeFunction final : public FunctionBase { class typeFunction final : public FunctionBase {
private: private:
std::vector<std::string> contents; std::vector<std::string> contents;
bool onlyCheckAndroidMagics = false, onlyCheckFileSystemMagics = false; bool onlyCheckAndroidMagics = false, onlyCheckFileSystemMagics = false;
int bufferSize = 4096; int bufferSize = 4096;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
class rebootFunction final : public FunctionBase { class rebootFunction final : public FunctionBase {
private: private:
std::string rebootTarget; std::string rebootTarget;
public: public:
CLI::App *cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override; [[nodiscard]] const char *name() const override;
}; };
} // namespace PartitionManager } // namespace PartitionManager
#endif // #ifndef FUNCTIONS_HPP #endif // #ifndef FUNCTIONS_HPP

312
srclib/libhelper/include/libhelper/lib.hpp Executable file → Normal file
View File

@@ -18,19 +18,19 @@
#define LIBHELPER_LIB_HPP #define LIBHELPER_LIB_HPP
#include <cstdint> #include <cstdint>
#include <string>
#include <string_view>
#include <sstream>
#include <exception> #include <exception>
#include <optional> #include <optional>
#include <sstream>
#include <string>
#include <string_view>
#ifndef ONLY_HELPER_MACROS #ifndef ONLY_HELPER_MACROS
enum LogLevels { enum LogLevels {
INFO = static_cast<int>('I'), INFO = static_cast<int>('I'),
WARNING = static_cast<int>('W'), WARNING = static_cast<int>('W'),
ERROR = static_cast<int>('E'), ERROR = static_cast<int>('E'),
ABORT = static_cast<int>('A') ABORT = static_cast<int>('A')
}; };
constexpr mode_t DEFAULT_FILE_PERMS = 0644; constexpr mode_t DEFAULT_FILE_PERMS = 0644;
@@ -40,127 +40,131 @@ constexpr int YES = 1;
constexpr int NO = 0; constexpr int NO = 0;
namespace Helper { namespace Helper {
// Logging // Logging
class Logger final { class Logger final {
private: private:
LogLevels _level; LogLevels _level;
std::ostringstream _oss; std::ostringstream _oss;
const char *_funcname, *_logFile, *_program_name, *_file; const char *_funcname, *_logFile, *_program_name, *_file;
int _line; int _line;
public: public:
Logger(LogLevels level, const char *func, const char *file, const char *name, const char *sfile, int line); Logger(LogLevels level, const char *func, const char *file, const char *name,
const char *sfile, int line);
~Logger(); ~Logger();
template<typename T> template <typename T> Logger &operator<<(const T &msg) {
Logger &operator<<(const T &msg) { _oss << msg;
_oss << msg; return *this;
return *this; }
}
Logger &operator<<(std::ostream & (*msg)(std::ostream &)); Logger &operator<<(std::ostream &(*msg)(std::ostream &));
}; };
// Throwable error class // Throwable error class
class Error final : public std::exception { class Error final : public std::exception {
private: private:
std::string _message; std::string _message;
public: public:
__attribute__((format(printf, 2, 3))) __attribute__((format(printf, 2, 3))) explicit Error(const char *format, ...);
explicit Error(const char *format, ...);
[[nodiscard]] const char *what() const noexcept override; [[nodiscard]] const char *what() const noexcept override;
}; };
// Close file descriptors and delete allocated array memory // Close file descriptors and delete allocated array memory
class garbageCollector { class garbageCollector {
private: private:
std::vector<char*> _ptrs_c; std::vector<char *> _ptrs_c;
std::vector<uint8_t*> _ptrs_u; std::vector<uint8_t *> _ptrs_u;
std::vector<FILE*> _fps; std::vector<FILE *> _fps;
std::vector<int> _fds; std::vector<int> _fds;
public: public:
~garbageCollector(); ~garbageCollector();
void delAfterProgress(char* &_ptr); void delAfterProgress(char *&_ptr);
void delAfterProgress(uint8_t* &_ptr); void delAfterProgress(uint8_t *&_ptr);
void delAfterProgress(FILE* &_fp); void delAfterProgress(FILE *&_fp);
void closeAfterProgress(int _fd); void closeAfterProgress(int _fd);
}; };
namespace LoggingProperties { namespace LoggingProperties {
extern std::string_view FILE, NAME; extern std::string_view FILE, NAME;
extern bool PRINT, DISABLE; extern bool PRINT, DISABLE;
void set(std::string_view name, std::string_view file); void set(std::string_view name, std::string_view file);
void setProgramName(std::string_view name); void setProgramName(std::string_view name);
void setLogFile(std::string_view file); void setLogFile(std::string_view file);
void setPrinting(int state); void setPrinting(int state);
void setLoggingState(int state); // Disable/enable logging void setLoggingState(int state); // Disable/enable logging
void reset(); void reset();
} // namespace LoggingProperties } // namespace LoggingProperties
// Checkers // Checkers
bool hasSuperUser(); bool hasSuperUser();
bool isExists(std::string_view entry); bool isExists(std::string_view entry);
bool fileIsExists(std::string_view file); bool fileIsExists(std::string_view file);
bool directoryIsExists(std::string_view directory); bool directoryIsExists(std::string_view directory);
bool linkIsExists(std::string_view entry); bool linkIsExists(std::string_view entry);
bool isLink(std::string_view entry); bool isLink(std::string_view entry);
bool isSymbolicLink(std::string_view entry); bool isSymbolicLink(std::string_view entry);
bool isHardLink(std::string_view entry); bool isHardLink(std::string_view entry);
bool areLinked(std::string_view entry1, std::string_view entry2); bool areLinked(std::string_view entry1, std::string_view entry2);
// File I/O // File I/O
bool writeFile(std::string_view file, std::string_view text); bool writeFile(std::string_view file, std::string_view text);
std::optional<std::string> readFile(std::string_view file); std::optional<std::string> readFile(std::string_view file);
// Creators // Creators
bool makeDirectory(std::string_view path); bool makeDirectory(std::string_view path);
bool makeRecursiveDirectory(std::string_view paths); bool makeRecursiveDirectory(std::string_view paths);
bool createFile(std::string_view path); bool createFile(std::string_view path);
bool createSymlink(std::string_view entry1, std::string_view entry2); bool createSymlink(std::string_view entry1, std::string_view entry2);
// Removers // Removers
bool eraseEntry(std::string_view entry); bool eraseEntry(std::string_view entry);
bool eraseDirectoryRecursive(std::string_view directory); bool eraseDirectoryRecursive(std::string_view directory);
// Getters // Getters
size_t fileSize(std::string_view file); size_t fileSize(std::string_view file);
std::string readSymlink(std::string_view entry); std::string readSymlink(std::string_view entry);
// SHA-256 // SHA-256
bool sha256Compare(std::string_view file1, std::string_view file2); bool sha256Compare(std::string_view file1, std::string_view file2);
std::optional<std::string> sha256Of(std::string_view path); std::optional<std::string> sha256Of(std::string_view path);
// Utilities // Utilities
bool copyFile(std::string_view file, std::string_view dest); bool copyFile(std::string_view file, std::string_view dest);
bool runCommand(std::string_view cmd); bool runCommand(std::string_view cmd);
bool confirmPropt(std::string_view message); bool confirmPropt(std::string_view message);
bool changeMode(std::string_view file, mode_t mode); bool changeMode(std::string_view file, mode_t mode);
bool changeOwner(std::string_view file, uid_t uid, gid_t gid); bool changeOwner(std::string_view file, uid_t uid, gid_t gid);
std::string currentWorkingDirectory(); std::string currentWorkingDirectory();
std::string currentDate(); std::string currentDate();
std::string currentTime(); std::string currentTime();
std::string runCommandWithOutput(std::string_view cmd); std::string runCommandWithOutput(std::string_view cmd);
std::string pathJoin(std::string base, std::string relative); std::string pathJoin(std::string base, std::string relative);
std::string pathBasename(std::string_view entry); std::string pathBasename(std::string_view entry);
std::string pathDirname(std::string_view entry); std::string pathDirname(std::string_view entry);
// Android // Android
std::string getProperty(std::string_view prop); std::string getProperty(std::string_view prop);
bool reboot(std::string_view arg); bool reboot(std::string_view arg);
// Library-specif // Library-specif
std::string getLibVersion(); std::string getLibVersion();
// Open input path with flags and add to integrity list. And return file descriptor // Open input path with flags and add to integrity list. And return file
[[nodiscard]] int openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, int flags, mode_t mode = 0000); // descriptor
[[nodiscard]] FILE* openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, const char* mode); [[nodiscard]] int openAndAddToCloseList(const std::string_view &path,
garbageCollector &collector, int flags,
mode_t mode = 0000);
[[nodiscard]] FILE *openAndAddToCloseList(const std::string_view &path,
garbageCollector &collector,
const char *mode);
} // namespace Helper } // namespace Helper
#endif // #ifndef ONLY_HELPER_MACROS #endif // #ifndef ONLY_HELPER_MACROS
@@ -171,62 +175,76 @@ namespace Helper {
#define MB(x) (KB(x) * 1024) // MB(4) = 4194304 (KB(4) * 1024) #define MB(x) (KB(x) * 1024) // MB(4) = 4194304 (KB(4) * 1024)
#define GB(x) (MB(x) * 1024) // GB(1) = 1073741824 (MB(1) * 1024) #define GB(x) (MB(x) * 1024) // GB(1) = 1073741824 (MB(1) * 1024)
#define TO_KB(x) (x / 1024) // TO_KB(1024) = 1 #define TO_KB(x) (x / 1024) // TO_KB(1024) = 1
#define TO_MB(x) (TO_KB(x) / 1024) // TO_MB(2048) (2048 / 1024) #define TO_MB(x) (TO_KB(x) / 1024) // TO_MB(2048) (2048 / 1024)
#define TO_GB(x) (TO_MB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024) #define TO_GB(x) (TO_MB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024)
#define STYLE_RESET "\033[0m" #define STYLE_RESET "\033[0m"
#define BOLD "\033[1m" #define BOLD "\033[1m"
#define FAINT "\033[2m" #define FAINT "\033[2m"
#define ITALIC "\033[3m" #define ITALIC "\033[3m"
#define UNDERLINE "\033[4m" #define UNDERLINE "\033[4m"
#define BLINC "\033[5m" #define BLINC "\033[5m"
#define FAST_BLINC "\033[6m" #define FAST_BLINC "\033[6m"
#define STRIKE_THROUGHT "\033[9m" #define STRIKE_THROUGHT "\033[9m"
#define NO_UNDERLINE "\033[24m" #define NO_UNDERLINE "\033[24m"
#define NO_BLINC "\033[25m" #define NO_BLINC "\033[25m"
#define RED "\033[31m" #define RED "\033[31m"
#define GREEN "\033[32m" #define GREEN "\033[32m"
#define YELLOW "\033[33m" #define YELLOW "\033[33m"
#ifndef NO_C_TYPE_HANDLERS #ifndef NO_C_TYPE_HANDLERS
// ABORT(message), ex: ABORT("memory error!\n") // ABORT(message), ex: ABORT("memory error!\n")
#define ABORT(msg) \ #define ABORT(msg) \
do { \ do { \
fprintf(stderr, "%s%sCRITICAL ERROR%s: %s\nAborting...\n", BOLD, RED, STYLE_RESET, msg); \ fprintf(stderr, "%s%sCRITICAL ERROR%s: %s\nAborting...\n", BOLD, RED, \
abort(); \ STYLE_RESET, msg); \
} while (0) abort(); \
} while (0)
// ERROR(message, exit), ex: ERROR("an error occured.\n", 1) // ERROR(message, exit), ex: ERROR("an error occured.\n", 1)
#define ERROR(msg, code) \ #define ERROR(msg, code) \
do { \ do { \
fprintf(stderr, "%s%sERROR%s: %s", BOLD, RED, STYLE_RESET, msg); \ fprintf(stderr, "%s%sERROR%s: %s", BOLD, RED, STYLE_RESET, msg); \
exit(code); \ exit(code); \
} while (0) } while (0)
// WARNING(message), ex: WARNING("using default setting.\n") // WARNING(message), ex: WARNING("using default setting.\n")
#define WARNING(msg) \ #define WARNING(msg) \
fprintf(stderr, "%s%sWARNING%s: %s", BOLD, YELLOW, STYLE_RESET, msg); fprintf(stderr, "%s%sWARNING%s: %s", BOLD, YELLOW, STYLE_RESET, msg);
// INFO(message), ex: INFO("operation ended.\n") // INFO(message), ex: INFO("operation ended.\n")
#define INFO(msg) \ #define INFO(msg) \
fprintf(stdout, "%s%sINFO%s: %s", BOLD, GREEN, STYLE_RESET, msg); fprintf(stdout, "%s%sINFO%s: %s", BOLD, GREEN, STYLE_RESET, msg);
#endif // #ifndef NO_C_TYPE_HANDLERS #endif // #ifndef NO_C_TYPE_HANDLERS
#define LOG(level) Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__) #define LOG(level) \
#define LOGN(name, level) Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), name, __FILE__, __LINE__) Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
#define LOGNF(name, file, level) Helper::Logger(level, file, name, __FILE__, __LINE__) Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGN(name, level) \
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
name, __FILE__, __LINE__)
#define LOGNF(name, file, level) \
Helper::Logger(level, file, name, __FILE__, __LINE__)
#define LOG_IF(level, condition) \ #define LOG_IF(level, condition) \
if (condition) Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__) if (condition) \
#define LOGN_IF(name, level, condition) \ Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
if (condition) Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), name, __FILE__, __LINE__) Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGNF_IF(name, file, level, condition) \ #define LOGN_IF(name, level, condition) \
if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__) if (condition) \
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
name, __FILE__, __LINE__)
#define LOGNF_IF(name, file, level, condition) \
if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__)
#define MKVERSION(name) \ #define MKVERSION(name) \
char vinfo[512]; \ char vinfo[512]; \
sprintf(vinfo, "%s %s [%s %s]\nBuildType: %s\nCMakeVersion: %s\nCompilerVersion: %s\nBuildFlags: %s", name, BUILD_VERSION, BUILD_DATE, BUILD_TIME, BUILD_TYPE, BUILD_CMAKE_VERSION, BUILD_COMPILER_VERSION, BUILD_FLAGS); \ sprintf(vinfo, \
return std::string(vinfo) "%s %s [%s %s]\nBuildType: %s\nCMakeVersion: %s\nCompilerVersion: " \
"%s\nBuildFlags: %s", \
name, BUILD_VERSION, BUILD_DATE, BUILD_TIME, BUILD_TYPE, \
BUILD_CMAKE_VERSION, BUILD_COMPILER_VERSION, BUILD_FLAGS); \
return std::string(vinfo)
#endif // #ifndef LIBHELPER_LIB_HPP #endif // #ifndef LIBHELPER_LIB_HPP

78
srclib/libhelper/src/Checkers.cpp Executable file → Normal file
View File

@@ -16,57 +16,55 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <sys/stat.h>
#include <unistd.h>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
#include <private/android_filesystem_config.h> #include <private/android_filesystem_config.h>
#include <sys/stat.h>
#include <unistd.h>
namespace Helper { namespace Helper {
bool hasSuperUser() { bool hasSuperUser() { return (getuid() == AID_ROOT); }
return (getuid() == AID_ROOT);
}
bool isExists(const std::string_view entry) { bool isExists(const std::string_view entry) {
struct stat st{}; struct stat st{};
return (stat(entry.data(), &st) == 0); return (stat(entry.data(), &st) == 0);
} }
bool fileIsExists(const std::string_view file) { bool fileIsExists(const std::string_view file) {
struct stat st{}; struct stat st{};
if (stat(file.data(), &st) != 0) return false; if (stat(file.data(), &st) != 0) return false;
return S_ISREG(st.st_mode); return S_ISREG(st.st_mode);
} }
bool directoryIsExists(const std::string_view directory) { bool directoryIsExists(const std::string_view directory) {
struct stat st{}; struct stat st{};
if (stat(directory.data(), &st) != 0) return false; if (stat(directory.data(), &st) != 0) return false;
return S_ISDIR(st.st_mode); return S_ISDIR(st.st_mode);
} }
bool linkIsExists(const std::string_view entry) { bool linkIsExists(const std::string_view entry) {
return (isLink(entry) || isHardLink(entry)); return (isLink(entry) || isHardLink(entry));
} }
bool isLink(const std::string_view entry) { bool isLink(const std::string_view entry) {
struct stat st{}; struct stat st{};
if (lstat(entry.data(), &st) != 0) return false; if (lstat(entry.data(), &st) != 0) return false;
return S_ISLNK(st.st_mode); return S_ISLNK(st.st_mode);
} }
bool isSymbolicLink(const std::string_view entry) { bool isSymbolicLink(const std::string_view entry) { return isLink(entry); }
return isLink(entry);
}
bool isHardLink(const std::string_view entry) { bool isHardLink(const std::string_view entry) {
struct stat st{}; struct stat st{};
if (lstat(entry.data(), &st) != 0) return false; if (lstat(entry.data(), &st) != 0) return false;
return (st.st_nlink >= 2); return (st.st_nlink >= 2);
} }
bool areLinked(const std::string_view entry1, const std::string_view entry2) { bool areLinked(const std::string_view entry1, const std::string_view entry2) {
const std::string st1 = (isSymbolicLink(entry1)) ? readSymlink(entry1) : std::string(entry1.data()); const std::string st1 = (isSymbolicLink(entry1)) ? readSymlink(entry1)
const std::string st2 = (isSymbolicLink(entry2)) ? readSymlink(entry2) : std::string(entry2.data()); : std::string(entry1.data());
const std::string st2 = (isSymbolicLink(entry2)) ? readSymlink(entry2)
: std::string(entry2.data());
return (st1 == st2); return (st1 == st2);
} }
} // namespace Helper } // namespace Helper

143
srclib/libhelper/src/Classes.cpp Executable file → Normal file
View File

@@ -14,86 +14,97 @@
limitations under the License. limitations under the License.
*/ */
#include <exception> #include <cerrno>
#include <sstream> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <unistd.h> #include <exception>
#include <libgen.h>
#include <cstdarg>
#include <cerrno>
#include <fcntl.h> #include <fcntl.h>
#include <libgen.h>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
#include <sstream>
#include <unistd.h>
namespace Helper { namespace Helper {
Error::Error(const char *format, ...) { Error::Error(const char *format, ...) {
char buf[1024]; char buf[1024];
va_list args; va_list args;
va_start(args, format); va_start(args, format);
vsnprintf(buf, sizeof(buf), format, args); vsnprintf(buf, sizeof(buf), format, args);
va_end(args); va_end(args);
_message = std::string(buf); _message = std::string(buf);
LOGN(HELPER, ERROR) << _message << std::endl; LOGN(HELPER, ERROR) << _message << std::endl;
} }
const char *Error::what() const noexcept { const char *Error::what() const noexcept { return _message.data(); }
return _message.data();
}
Logger::Logger(const LogLevels level, const char *func, const char *file, const char *name, const char *sfile, Logger::Logger(const LogLevels level, const char *func, const char *file,
const int line) : _level(level), _funcname(func), _logFile(file), _program_name(name), _file(sfile), const char *name, const char *sfile, const int line)
_line(line) { : _level(level), _funcname(func), _logFile(file), _program_name(name),
} _file(sfile), _line(line) {}
Logger::~Logger() { Logger::~Logger() {
if (LoggingProperties::DISABLE) return; if (LoggingProperties::DISABLE) return;
char str[1024]; char str[1024];
snprintf(str, sizeof(str), "<%c> [ <prog %s> <on %s:%d> %s %s] %s(): %s", snprintf(str, sizeof(str), "<%c> [ <prog %s> <on %s:%d> %s %s] %s(): %s",
static_cast<char>(_level), static_cast<char>(_level), _program_name,
_program_name, basename(const_cast<char *>(_file)), _line, currentDate().data(),
basename(const_cast<char *>(_file)), currentTime().data(), _funcname, _oss.str().data());
_line,
currentDate().data(),
currentTime().data(),
_funcname,
_oss.str().data());
if (!isExists(_logFile)) { if (!isExists(_logFile)) {
if (const int fd = open(_logFile, O_WRONLY | O_CREAT, DEFAULT_EXTENDED_FILE_PERMS); fd != -1) close(fd); if (const int fd =
else { open(_logFile, O_WRONLY | O_CREAT, DEFAULT_EXTENDED_FILE_PERMS);
LoggingProperties::setLogFile("last_logs.log"); fd != -1)
LOGN(HELPER, INFO) << "Cannot create log file: " << _logFile << ": " << strerror(errno) << close(fd);
" New logging file: last_logs.log (this file)." << std::endl; else {
} LoggingProperties::setLogFile("last_logs.log");
} LOGN(HELPER, INFO) << "Cannot create log file: " << _logFile << ": "
<< strerror(errno)
<< " New logging file: last_logs.log (this file)."
<< std::endl;
}
}
if (FILE *fp = fopen(_logFile, "a"); fp != nullptr) { if (FILE *fp = fopen(_logFile, "a"); fp != nullptr) {
fprintf(fp, "%s", str); fprintf(fp, "%s", str);
fclose(fp); fclose(fp);
} else { } else {
LoggingProperties::setLogFile("last_logs.log"); LoggingProperties::setLogFile("last_logs.log");
LOGN(HELPER, INFO) << "Cannot write logs to log file: " << _logFile << ": " << strerror(errno) << LOGN(HELPER, INFO)
" Logging file setting up as: last_logs.log (this file)." << std::endl; << "Cannot write logs to log file: " << _logFile << ": "
} << strerror(errno)
<< " Logging file setting up as: last_logs.log (this file)."
<< std::endl;
}
if (LoggingProperties::PRINT) printf("%s", str); if (LoggingProperties::PRINT) printf("%s", str);
} }
Logger &Logger::operator<<(std::ostream & (*msg)(std::ostream &)) { Logger &Logger::operator<<(std::ostream &(*msg)(std::ostream &)) {
_oss << msg; _oss << msg;
return *this; return *this;
} }
garbageCollector::~garbageCollector() { garbageCollector::~garbageCollector() {
for (const auto& ptr : _ptrs_c) delete[] ptr; for (const auto &ptr : _ptrs_c)
for (const auto& ptr : _ptrs_u) delete[] ptr; delete[] ptr;
for (const auto& fd : _fds) close(fd); for (const auto &ptr : _ptrs_u)
for (const auto& fp : _fps) fclose(fp); delete[] ptr;
} for (const auto &fd : _fds)
close(fd);
for (const auto &fp : _fps)
fclose(fp);
}
void garbageCollector::delAfterProgress(char* &_ptr) { _ptrs_c.push_back(_ptr); } void garbageCollector::delAfterProgress(char *&_ptr) {
void garbageCollector::delAfterProgress(uint8_t *&_ptr) { _ptrs_u.push_back(_ptr); } _ptrs_c.push_back(_ptr);
void garbageCollector::closeAfterProgress(const int _fd) { _fds.push_back(_fd); } }
void garbageCollector::delAfterProgress(FILE* &_fp) { _fps.push_back(_fp); } void garbageCollector::delAfterProgress(uint8_t *&_ptr) {
_ptrs_u.push_back(_ptr);
}
void garbageCollector::closeAfterProgress(const int _fd) {
_fds.push_back(_fd);
}
void garbageCollector::delAfterProgress(FILE *&_fp) { _fps.push_back(_fp); }
} // namespace Helper } // namespace Helper

286
srclib/libhelper/src/FileUtil.cpp Executable file → Normal file
View File

@@ -14,187 +14,199 @@
limitations under the License. limitations under the License.
*/ */
#include <string> #include <cerrno>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <cerrno>
#include <fcntl.h>
#include <dirent.h> #include <dirent.h>
#include <unistd.h> #include <fcntl.h>
#include <sys/stat.h>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
namespace Helper { namespace Helper {
bool writeFile(const std::string_view file, const std::string_view text) { bool writeFile(const std::string_view file, const std::string_view text) {
LOGN(HELPER, INFO) << "write \"" << text << "\" to " << file << "requested." << std::endl; LOGN(HELPER, INFO) << "write \"" << text << "\" to " << file << "requested."
garbageCollector collector; << std::endl;
garbageCollector collector;
FILE *fp = openAndAddToCloseList(file, collector, "a"); FILE *fp = openAndAddToCloseList(file, collector, "a");
if (fp == nullptr) return false; if (fp == nullptr) return false;
fprintf(fp, "%s", text.data()); fprintf(fp, "%s", text.data());
LOGN(HELPER, INFO) << "write " << file << " successfully." << std::endl; LOGN(HELPER, INFO) << "write " << file << " successfully." << std::endl;
return true; return true;
} }
std::optional<std::string> readFile(const std::string_view file) { std::optional<std::string> readFile(const std::string_view file) {
LOGN(HELPER, INFO) << "read " << file << " requested." << std::endl; LOGN(HELPER, INFO) << "read " << file << " requested." << std::endl;
garbageCollector collector; garbageCollector collector;
FILE *fp = openAndAddToCloseList(file, collector, "r"); FILE *fp = openAndAddToCloseList(file, collector, "r");
if (fp == nullptr) return std::nullopt; if (fp == nullptr) return std::nullopt;
char buffer[1024]; char buffer[1024];
std::string str; std::string str;
while (fgets(buffer, sizeof(buffer), fp)) str += buffer; while (fgets(buffer, sizeof(buffer), fp))
str += buffer;
LOGN(HELPER, INFO) << "read " << file << " successfully, read text: \"" << str << "\"" << std::endl; LOGN(HELPER, INFO) << "read " << file << " successfully, read text: \"" << str
return str; << "\"" << std::endl;
} return str;
}
bool copyFile(const std::string_view file, const std::string_view dest) { bool copyFile(const std::string_view file, const std::string_view dest) {
LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " requested." << std::endl; LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " requested."
garbageCollector collector; << std::endl;
garbageCollector collector;
const int src_fd = openAndAddToCloseList(file.data(), collector, O_RDONLY); const int src_fd = openAndAddToCloseList(file.data(), collector, O_RDONLY);
if (src_fd == -1) return false; if (src_fd == -1) return false;
const int dst_fd = openAndAddToCloseList(dest.data(), collector, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_PERMS); const int dst_fd = openAndAddToCloseList(
if (dst_fd == -1) return false; dest.data(), collector, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_PERMS);
if (dst_fd == -1) return false;
char buffer[512]; char buffer[512];
ssize_t br; ssize_t br;
while ((br = read(src_fd, buffer, 512)) > 0) { while ((br = read(src_fd, buffer, 512)) > 0) {
if (const ssize_t bw = write(dst_fd, buffer, br); bw != br) return false; if (const ssize_t bw = write(dst_fd, buffer, br); bw != br) return false;
} }
if (br == -1) return false; if (br == -1) return false;
LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " successfully." << std::endl; LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " successfully."
return true; << std::endl;
} return true;
}
bool makeDirectory(const std::string_view path) { bool makeDirectory(const std::string_view path) {
if (isExists(path)) return false; if (isExists(path)) return false;
LOGN(HELPER, INFO) << "trying making directory: " << path << std::endl; LOGN(HELPER, INFO) << "trying making directory: " << path << std::endl;
return (mkdir(path.data(), DEFAULT_DIR_PERMS) == 0); return (mkdir(path.data(), DEFAULT_DIR_PERMS) == 0);
} }
bool makeRecursiveDirectory(const std::string_view paths) { bool makeRecursiveDirectory(const std::string_view paths) {
LOGN(HELPER, INFO) << "make recursive directory requested: " << paths << std::endl; LOGN(HELPER, INFO) << "make recursive directory requested: " << paths
<< std::endl;
char tmp[PATH_MAX]; char tmp[PATH_MAX];
snprintf(tmp, sizeof(tmp), "%s", paths.data()); snprintf(tmp, sizeof(tmp), "%s", paths.data());
if (const size_t len = strlen(tmp); tmp[len - 1] == '/') tmp[len - 1] = '\0'; if (const size_t len = strlen(tmp); tmp[len - 1] == '/') tmp[len - 1] = '\0';
for (char *p = tmp + 1; *p; p++) { for (char *p = tmp + 1; *p; p++) {
if (*p == '/') { if (*p == '/') {
*p = '\0'; *p = '\0';
if (access(tmp, F_OK) != 0) { if (access(tmp, F_OK) != 0) {
if (mkdir(tmp, DEFAULT_DIR_PERMS) != 0 if (mkdir(tmp, DEFAULT_DIR_PERMS) != 0 && errno != EEXIST) return false;
&& errno != EEXIST) }
return false; *p = '/';
} }
*p = '/'; }
}
}
if (access(tmp, F_OK) != 0) { if (access(tmp, F_OK) != 0) {
if (mkdir(tmp, DEFAULT_DIR_PERMS) != 0 && errno != EEXIST) return false; if (mkdir(tmp, DEFAULT_DIR_PERMS) != 0 && errno != EEXIST) return false;
} }
LOGN(HELPER, INFO) << "" << paths << " successfully created." << std::endl; LOGN(HELPER, INFO) << "" << paths << " successfully created." << std::endl;
return true; return true;
} }
bool createFile(const std::string_view path) { bool createFile(const std::string_view path) {
LOGN(HELPER, INFO) << "create file request: " << path << std::endl; LOGN(HELPER, INFO) << "create file request: " << path << std::endl;
if (isExists(path)) return false; if (isExists(path)) return false;
const int fd = open(path.data(), O_RDONLY | O_CREAT, DEFAULT_FILE_PERMS); const int fd = open(path.data(), O_RDONLY | O_CREAT, DEFAULT_FILE_PERMS);
if (fd == -1) return false; if (fd == -1) return false;
close(fd); close(fd);
LOGN(HELPER, INFO) << "create file \"" << path << "\" successfull." << std::endl; LOGN(HELPER, INFO) << "create file \"" << path << "\" successfull."
return true; << std::endl;
} return true;
}
bool createSymlink(const std::string_view entry1, const std::string_view entry2) { bool createSymlink(const std::string_view entry1,
LOGN(HELPER, INFO) << "symlink \"" << entry1 << "\" to \"" << entry2 << "\" requested." << std::endl; const std::string_view entry2) {
if (const int ret = symlink(entry1.data(), entry2.data()); ret != 0) return false; LOGN(HELPER, INFO) << "symlink \"" << entry1 << "\" to \"" << entry2
<< "\" requested." << std::endl;
if (const int ret = symlink(entry1.data(), entry2.data()); ret != 0)
return false;
LOGN(HELPER, INFO) << "\"" << entry1 << "\" symlinked to \"" << entry2 << "\" successfully." << std::endl; LOGN(HELPER, INFO) << "\"" << entry1 << "\" symlinked to \"" << entry2
return true; << "\" successfully." << std::endl;
} return true;
}
bool eraseEntry(const std::string_view entry) { bool eraseEntry(const std::string_view entry) {
LOGN(HELPER, INFO) << "erase \"" << entry << "\" requested." << std::endl; LOGN(HELPER, INFO) << "erase \"" << entry << "\" requested." << std::endl;
if (const int ret = remove(entry.data()); ret != 0) return false; if (const int ret = remove(entry.data()); ret != 0) return false;
LOGN(HELPER, INFO) << "\"" << entry << "\" erased successfully." << std::endl; LOGN(HELPER, INFO) << "\"" << entry << "\" erased successfully." << std::endl;
return true; return true;
} }
bool eraseDirectoryRecursive(const std::string_view directory) { bool eraseDirectoryRecursive(const std::string_view directory) {
LOGN(HELPER, INFO) << "erase recursive requested: " << directory << std::endl; LOGN(HELPER, INFO) << "erase recursive requested: " << directory << std::endl;
struct stat buf{}; struct stat buf{};
dirent *entry; dirent *entry;
DIR *dir = opendir(directory.data()); DIR *dir = opendir(directory.data());
if (dir == nullptr) return false; if (dir == nullptr) return false;
while ((entry = readdir(dir)) != nullptr) { while ((entry = readdir(dir)) != nullptr) {
char fullpath[PATH_MAX]; char fullpath[PATH_MAX];
if (strcmp(entry->d_name, ".") == 0 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|| strcmp(entry->d_name, "..") == 0) continue;
continue;
snprintf(fullpath, sizeof(fullpath), "%s/%s", directory.data(), entry->d_name); snprintf(fullpath, sizeof(fullpath), "%s/%s", directory.data(),
entry->d_name);
if (lstat(fullpath, &buf) == -1) { if (lstat(fullpath, &buf) == -1) {
closedir(dir); closedir(dir);
return false; return false;
} }
if (S_ISDIR(buf.st_mode)) { if (S_ISDIR(buf.st_mode)) {
if (!eraseDirectoryRecursive(fullpath)) { if (!eraseDirectoryRecursive(fullpath)) {
closedir(dir); closedir(dir);
return false; return false;
} }
} else { } else {
if (unlink(fullpath) == -1) { if (unlink(fullpath) == -1) {
closedir(dir); closedir(dir);
return false; return false;
} }
} }
} }
closedir(dir); closedir(dir);
if (rmdir(directory.data()) == -1) return false; if (rmdir(directory.data()) == -1) return false;
LOGN(HELPER, INFO) << "\"" << directory << "\" successfully erased." << std::endl; LOGN(HELPER, INFO) << "\"" << directory << "\" successfully erased."
return true; << std::endl;
} return true;
}
std::string readSymlink(const std::string_view entry) { std::string readSymlink(const std::string_view entry) {
LOGN(HELPER, INFO) << "read symlink request: " << entry << std::endl; LOGN(HELPER, INFO) << "read symlink request: " << entry << std::endl;
char target[PATH_MAX]; char target[PATH_MAX];
const ssize_t len = readlink(entry.data(), target, (sizeof(target) - 1)); const ssize_t len = readlink(entry.data(), target, (sizeof(target) - 1));
if (len == -1) return entry.data(); if (len == -1) return entry.data();
target[len] = '\0'; target[len] = '\0';
LOGN(HELPER, INFO) << "\"" << entry << "\" symlink to \"" << target << "\"" << std::endl; LOGN(HELPER, INFO) << "\"" << entry << "\" symlink to \"" << target << "\""
return target; << std::endl;
} return target;
}
size_t fileSize(const std::string_view file) { size_t fileSize(const std::string_view file) {
LOGN(HELPER, INFO) << "get file size request: " << file << std::endl; LOGN(HELPER, INFO) << "get file size request: " << file << std::endl;
struct stat st{}; struct stat st{};
if (stat(file.data(), &st) != 0) return false; if (stat(file.data(), &st) != 0) return false;
return static_cast<size_t>(st.st_size); return static_cast<size_t>(st.st_size);
} }
} // namespace Helper } // namespace Helper

51
srclib/libhelper/src/Sha256.cpp Executable file → Normal file
View File

@@ -15,36 +15,43 @@
*/ */
#include <fstream> #include <fstream>
#include <vector>
#include <string>
#include <iostream> #include <iostream>
#include <libhelper/lib.hpp>
#include <optional> #include <optional>
#include <picosha2.h> #include <picosha2.h>
#include <string>
#include <sys/stat.h> #include <sys/stat.h>
#include <libhelper/lib.hpp> #include <vector>
namespace Helper { namespace Helper {
std::optional<std::string> sha256Of(const std::string_view path) { std::optional<std::string> sha256Of(const std::string_view path) {
LOGN(HELPER, INFO) << "get sha256 of \"" << path << LOGN(HELPER, INFO)
"\" request. Getting full path (if input is link and exists)." << std::endl; << "get sha256 of \"" << path
std::string fp = (isLink(path)) ? readSymlink(path) : std::string(path); << "\" request. Getting full path (if input is link and exists)."
<< std::endl;
std::string fp = (isLink(path)) ? readSymlink(path) : std::string(path);
if (!fileIsExists(fp)) throw Error("Is not exists or not file: %s", fp.data()); if (!fileIsExists(fp))
throw Error("Is not exists or not file: %s", fp.data());
if (const std::ifstream file(fp, std::ios::binary); !file) throw Error("Cannot open file: %s", fp.data()); if (const std::ifstream file(fp, std::ios::binary); !file)
throw Error("Cannot open file: %s", fp.data());
std::vector<unsigned char> hash(picosha2::k_digest_size); std::vector<unsigned char> hash(picosha2::k_digest_size);
picosha2::hash256(fp, hash.begin(), hash.end()); picosha2::hash256(fp, hash.begin(), hash.end());
LOGN(HELPER, INFO) << "get sha256 of \"" << path << "\" successfully." << std::endl; LOGN(HELPER, INFO) << "get sha256 of \"" << path << "\" successfully."
return picosha2::bytes_to_hex_string(hash.begin(), hash.end()); << std::endl;
} return picosha2::bytes_to_hex_string(hash.begin(), hash.end());
}
bool sha256Compare(const std::string_view file1, const std::string_view file2) { bool sha256Compare(const std::string_view file1, const std::string_view file2) {
LOGN(HELPER, INFO) << "comparing sha256 signatures of input files." << std::endl; LOGN(HELPER, INFO) << "comparing sha256 signatures of input files."
const auto f1 = sha256Of(file1); << std::endl;
const auto f2 = sha256Of(file2); const auto f1 = sha256Of(file1);
if (f1->empty() || f2->empty()) return false; const auto f2 = sha256Of(file2);
LOGN_IF(HELPER, INFO, *f1 == *f2) << "(): input files is contains same sha256 signature." << std::endl; if (f1->empty() || f2->empty()) return false;
return (*f1 == *f2); LOGN_IF(HELPER, INFO, *f1 == *f2)
} << "(): input files is contains same sha256 signature." << std::endl;
return (*f1 == *f2);
}
} // namespace Helper } // namespace Helper

308
srclib/libhelper/src/Utilities.cpp Executable file → Normal file
View File

@@ -14,201 +14,207 @@
limitations under the License. limitations under the License.
*/ */
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cutils/android_reboot.h>
#include <fcntl.h>
#include <generated/buildInfo.hpp>
#include <iostream> #include <iostream>
#include <libgen.h>
#include <libhelper/lib.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <ctime>
#include <fcntl.h>
#include <libgen.h>
#include <libhelper/lib.hpp>
#include <generated/buildInfo.hpp>
#include <sys/stat.h>
#include <sys/_system_properties.h> #include <sys/_system_properties.h>
#include <cutils/android_reboot.h> #include <sys/stat.h>
#include <unistd.h>
// From system/core/libcutils/android_reboot.cpp android16-s2-release // From system/core/libcutils/android_reboot.cpp android16-s2-release
int android_reboot(const unsigned cmd, int /*flags*/, const char* arg) { int android_reboot(const unsigned cmd, int /*flags*/, const char *arg) {
int ret; int ret;
const char* restart_cmd = nullptr; const char *restart_cmd = nullptr;
char* prop_value; char *prop_value;
switch (cmd) { switch (cmd) {
case ANDROID_RB_RESTART: // deprecated case ANDROID_RB_RESTART: // deprecated
case ANDROID_RB_RESTART2: case ANDROID_RB_RESTART2:
restart_cmd = "reboot"; restart_cmd = "reboot";
break; break;
case ANDROID_RB_POWEROFF: case ANDROID_RB_POWEROFF:
restart_cmd = "shutdown"; restart_cmd = "shutdown";
break; break;
case ANDROID_RB_THERMOFF: case ANDROID_RB_THERMOFF:
restart_cmd = "shutdown,thermal"; restart_cmd = "shutdown,thermal";
break; break;
} }
if (!restart_cmd) return -1; if (!restart_cmd) return -1;
if (arg && arg[0]) ret = asprintf(&prop_value, "%s,%s", restart_cmd, arg); if (arg && arg[0]) ret = asprintf(&prop_value, "%s,%s", restart_cmd, arg);
else ret = asprintf(&prop_value, "%s", restart_cmd); else ret = asprintf(&prop_value, "%s", restart_cmd);
if (ret < 0) return -1; if (ret < 0) return -1;
ret = __system_property_set(ANDROID_RB_PROPERTY, prop_value); ret = __system_property_set(ANDROID_RB_PROPERTY, prop_value);
free(prop_value); free(prop_value);
return ret; return ret;
} }
namespace Helper { namespace Helper {
namespace LoggingProperties { namespace LoggingProperties {
std::string_view FILE = "last_logs.log", NAME = "main"; std::string_view FILE = "last_logs.log", NAME = "main";
bool PRINT = NO, DISABLE = NO; bool PRINT = NO, DISABLE = NO;
void reset() { void reset() {
FILE = "last_logs.log"; FILE = "last_logs.log";
NAME = "main"; NAME = "main";
PRINT = NO; PRINT = NO;
} }
void set(std::string_view file, std::string_view name) { void set(std::string_view file, std::string_view name) {
if (file.data() != nullptr) FILE = file; if (file.data() != nullptr) FILE = file;
if (name.data() != nullptr) NAME = name; if (name.data() != nullptr) NAME = name;
} }
void setProgramName(const std::string_view name) { NAME = name; } void setProgramName(const std::string_view name) { NAME = name; }
void setLogFile(const std::string_view file) { FILE = file; } void setLogFile(const std::string_view file) { FILE = file; }
void setPrinting(const int state) { void setPrinting(const int state) {
if (state == 1 || state == 0) PRINT = state; if (state == 1 || state == 0) PRINT = state;
else PRINT = NO; else PRINT = NO;
} }
void setLoggingState(const int state) { void setLoggingState(const int state) {
if (state == 1 || state == 0) DISABLE = state; if (state == 1 || state == 0) DISABLE = state;
else DISABLE = NO; else DISABLE = NO;
} }
} // namespace LoggingProperties } // namespace LoggingProperties
bool runCommand(const std::string_view cmd) { bool runCommand(const std::string_view cmd) {
LOGN(HELPER, INFO) << "run command request: " << cmd << std::endl; LOGN(HELPER, INFO) << "run command request: " << cmd << std::endl;
return (system(cmd.data()) == 0) ? true : false; return (system(cmd.data()) == 0) ? true : false;
} }
bool confirmPropt(const std::string_view message) { bool confirmPropt(const std::string_view message) {
LOGN(HELPER, INFO) << "create confirm propt request. Creating." << std::endl; LOGN(HELPER, INFO) << "create confirm propt request. Creating." << std::endl;
char p; char p;
printf("%s [ y / n ]: ", message.data()); printf("%s [ y / n ]: ", message.data());
std::cin >> p; std::cin >> p;
if (p == 'y' || p == 'Y') return true; if (p == 'y' || p == 'Y') return true;
if (p == 'n' || p == 'N') return false; if (p == 'n' || p == 'N') return false;
printf("Unexpected answer: '%c'. Try again.\n", p); printf("Unexpected answer: '%c'. Try again.\n", p);
return confirmPropt(message); return confirmPropt(message);
} }
std::string currentWorkingDirectory() { std::string currentWorkingDirectory() {
char cwd[1024]; char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) == nullptr) return {}; if (getcwd(cwd, sizeof(cwd)) == nullptr) return {};
return cwd; return cwd;
} }
std::string currentDate() { std::string currentDate() {
const time_t t = time(nullptr); const time_t t = time(nullptr);
if (const tm *date = localtime(&t)) if (const tm *date = localtime(&t))
return std::string( return std::string(std::to_string(date->tm_mday) + "/" +
std::to_string(date->tm_mday) + "/" + std::to_string(date->tm_mon + 1) + "/" +
std::to_string(date->tm_mon + 1) + "/" + std::to_string(date->tm_year + 1900));
std::to_string(date->tm_year + 1900)); return "--/--/----";
return "--/--/----"; }
}
std::string currentTime() { std::string currentTime() {
const time_t t = time(nullptr); const time_t t = time(nullptr);
if (const tm *date = localtime(&t)) if (const tm *date = localtime(&t))
return std::string( return std::string(std::to_string(date->tm_hour) + ":" +
std::to_string(date->tm_hour) + ":" + std::to_string(date->tm_min) + ":" +
std::to_string(date->tm_min) + ":" + std::to_string(date->tm_sec));
std::to_string(date->tm_sec)); return "--:--:--";
return "--:--:--"; }
}
std::string runCommandWithOutput(const std::string_view cmd) { std::string runCommandWithOutput(const std::string_view cmd) {
LOGN(HELPER, INFO) << "run command and catch out request: " << cmd << std::endl; LOGN(HELPER, INFO) << "run command and catch out request: " << cmd
<< std::endl;
FILE *pipe = popen(cmd.data(), "r"); FILE *pipe = popen(cmd.data(), "r");
if (!pipe) return {}; if (!pipe) return {};
std::unique_ptr<FILE, decltype(&pclose)> pipe_holder(pipe, pclose); std::unique_ptr<FILE, decltype(&pclose)> pipe_holder(pipe, pclose);
std::string output; std::string output;
char buffer[1024]; char buffer[1024];
while (fgets(buffer, sizeof(buffer), pipe_holder.get()) != nullptr) output += buffer; while (fgets(buffer, sizeof(buffer), pipe_holder.get()) != nullptr)
output += buffer;
return output; return output;
} }
std::string pathJoin(std::string base, std::string relative) { std::string pathJoin(std::string base, std::string relative) {
if (base.back() != '/') base += '/'; if (base.back() != '/') base += '/';
if (relative[0] == '/') relative.erase(0, 1); if (relative[0] == '/') relative.erase(0, 1);
base += relative; base += relative;
return base; return base;
} }
std::string pathBasename(const std::string_view entry) { std::string pathBasename(const std::string_view entry) {
char *base = basename(const_cast<char *>(entry.data())); char *base = basename(const_cast<char *>(entry.data()));
return (base == nullptr) ? std::string() : std::string(base); return (base == nullptr) ? std::string() : std::string(base);
} }
std::string pathDirname(const std::string_view entry) { std::string pathDirname(const std::string_view entry) {
char *base = dirname(const_cast<char *>(entry.data())); char *base = dirname(const_cast<char *>(entry.data()));
return (base == nullptr) ? std::string() : std::string(base); return (base == nullptr) ? std::string() : std::string(base);
} }
bool changeMode(const std::string_view file, const mode_t mode) { bool changeMode(const std::string_view file, const mode_t mode) {
LOGN(HELPER, INFO) << "change mode request: " << file << ". As mode: " << mode << std::endl; LOGN(HELPER, INFO) << "change mode request: " << file << ". As mode: " << mode
return chmod(file.data(), mode) == 0; << std::endl;
} return chmod(file.data(), mode) == 0;
}
bool changeOwner(const std::string_view file, const uid_t uid, const gid_t gid) { bool changeOwner(const std::string_view file, const uid_t uid,
LOGN(HELPER, INFO) << "change owner request: " << file << ". As owner:group: " << uid << ":" << gid << std::endl; const gid_t gid) {
return chown(file.data(), uid, gid) == 0; LOGN(HELPER, INFO) << "change owner request: " << file
} << ". As owner:group: " << uid << ":" << gid << std::endl;
return chown(file.data(), uid, gid) == 0;
}
int openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, const int flags, const mode_t mode) { int openAndAddToCloseList(const std::string_view &path,
const int fd = mode == 0 ? open(path.data(), flags) : open(path.data(), flags, mode); garbageCollector &collector, const int flags,
collector.closeAfterProgress(fd); const mode_t mode) {
return fd; const int fd =
} mode == 0 ? open(path.data(), flags) : open(path.data(), flags, mode);
collector.closeAfterProgress(fd);
return fd;
}
FILE* openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, const char* mode) { FILE *openAndAddToCloseList(const std::string_view &path,
FILE *fp = fopen(path.data(), mode); garbageCollector &collector, const char *mode) {
collector.delAfterProgress(fp); FILE *fp = fopen(path.data(), mode);
return fp; collector.delAfterProgress(fp);
} return fp;
}
std::string getProperty(const std::string_view prop) { std::string getProperty(const std::string_view prop) {
char val[PROP_VALUE_MAX]; char val[PROP_VALUE_MAX];
const int x = __system_property_get(prop.data(), val); const int x = __system_property_get(prop.data(), val);
return x > 0 ? val : "ERROR"; return x > 0 ? val : "ERROR";
} }
bool reboot(const std::string_view arg) { bool reboot(const std::string_view arg) {
LOGN(HELPER, INFO) << "reboot request sent!!!" << std::endl; LOGN(HELPER, INFO) << "reboot request sent!!!" << std::endl;
unsigned cmd = ANDROID_RB_RESTART2; unsigned cmd = ANDROID_RB_RESTART2;
if (const std::string prop = getProperty("ro.build.version.sdk"); prop != "ERROR") { if (const std::string prop = getProperty("ro.build.version.sdk");
if (std::stoi(prop) < 26) cmd = ANDROID_RB_RESTART; prop != "ERROR") {
} if (std::stoi(prop) < 26) cmd = ANDROID_RB_RESTART;
}
return android_reboot(cmd, 0, arg.empty() ? nullptr : arg.data()) != -1; return android_reboot(cmd, 0, arg.empty() ? nullptr : arg.data()) != -1;
} }
std::string getLibVersion() { std::string getLibVersion() { MKVERSION("libhelper"); }
MKVERSION("libhelper");
}
} // namespace Helper } // namespace Helper

163
srclib/libhelper/tests/test.cpp Executable file → Normal file
View File

@@ -19,85 +19,116 @@
#include <iostream> #include <iostream>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
char* TEST_DIR = nullptr; char *TEST_DIR = nullptr;
std::string test_path(const char* file) std::string test_path(const char *file) {
{ std::string end = std::string(TEST_DIR) + "/" + file;
std::string end = std::string(TEST_DIR) + "/" + file; return end;
return end;
} }
int main(int argc, char** argv) int main(int argc, char **argv) {
{ if (argc < 2) return 2;
if (argc < 2) return 2; else TEST_DIR = argv[1];
else TEST_DIR = argv[1];
try { try {
std::cout << "Has super user?; " << std::boolalpha << Helper::hasSuperUser() << std::endl; std::cout << "Has super user?; " << std::boolalpha << Helper::hasSuperUser()
std::cout << "file.txt is exists?; " << std::boolalpha << Helper::isExists(test_path("file.txt")) << std::endl; << std::endl;
std::cout << "'file.txt' file is exists?; " << std::boolalpha << Helper::fileIsExists(test_path("file")) << std::endl; std::cout << "file.txt is exists?; " << std::boolalpha
std::cout << "'dir' directory is exists?; " << std::boolalpha << Helper::directoryIsExists(test_path("dir")) << std::endl; << Helper::isExists(test_path("file.txt")) << std::endl;
std::cout << "'linkdir' is link?; " << std::boolalpha << Helper::isLink(test_path("linkdir")) << std::endl; std::cout << "'file.txt' file is exists?; " << std::boolalpha
std::cout << "'linkdir' is symlink?; " << std::boolalpha << Helper::isSymbolicLink(test_path("linkdir")) << std::endl; << Helper::fileIsExists(test_path("file")) << std::endl;
std::cout << "'linkdir' is hardlink?; " << std::boolalpha << Helper::isHardLink(test_path("linkdir")) << std::endl; std::cout << "'dir' directory is exists?; " << std::boolalpha
std::cout << "'linkdir' is symlink to 'dir'?; " << std::boolalpha << Helper::areLinked(test_path("linkdir"), test_path("dir")) << std::endl; << Helper::directoryIsExists(test_path("dir")) << std::endl;
std::cout << "'linkdir' is link?; " << std::boolalpha
<< Helper::isLink(test_path("linkdir")) << std::endl;
std::cout << "'linkdir' is symlink?; " << std::boolalpha
<< Helper::isSymbolicLink(test_path("linkdir")) << std::endl;
std::cout << "'linkdir' is hardlink?; " << std::boolalpha
<< Helper::isHardLink(test_path("linkdir")) << std::endl;
std::cout << "'linkdir' is symlink to 'dir'?; " << std::boolalpha
<< Helper::areLinked(test_path("linkdir"), test_path("dir"))
<< std::endl;
if (!Helper::writeFile("file.txt", "hello world")) if (!Helper::writeFile("file.txt", "hello world"))
throw Helper::Error("Cannor write \"hello world\" in 'file.txt'"); throw Helper::Error("Cannor write \"hello world\" in 'file.txt'");
else else std::cout << "file.txt writed." << std::endl;
std::cout << "file.txt writed." << std::endl;
auto content = Helper::readFile("file.txt"); auto content = Helper::readFile("file.txt");
if (!content) if (!content) throw Helper::Error("Cannot read 'file.txt'");
throw Helper::Error("Cannot read 'file.txt'"); else std::cout << "'file.txt': " << *content << std::endl;
else
std::cout << "'file.txt': " << *content << std::endl;
std::cout << "Making directory 'dir2': " << std::boolalpha << Helper::makeDirectory(test_path("dir2")) << std::endl; std::cout << "Making directory 'dir2': " << std::boolalpha
std::cout << "Making recursive directories 'dir3/x/y': " << std::boolalpha << Helper::makeRecursiveDirectory(test_path("dir3/x/y")) << std::endl; << Helper::makeDirectory(test_path("dir2")) << std::endl;
std::cout << "Create 'file2.txt': " << std::boolalpha << Helper::createFile(test_path("file2.txt")) << std::endl; std::cout << "Making recursive directories 'dir3/x/y': " << std::boolalpha
std::cout << "Create symlink 'file2.txt' to 'file2lnk.txt': " << std::boolalpha << Helper::createSymlink(test_path("file2.txt"), test_path("file2lnk.txt")) << std::endl; << Helper::makeRecursiveDirectory(test_path("dir3/x/y"))
std::cout << "Size of 'file2.txt': " << Helper::fileSize(test_path("file2.txt")) << std::endl; << std::endl;
std::cout << "Erasing 'file.txt': " << std::boolalpha << Helper::eraseEntry(test_path("file.txt")) << std::endl; std::cout << "Create 'file2.txt': " << std::boolalpha
std::cout << "Erasing 'dir2': " << std::boolalpha << Helper::eraseEntry(test_path("dir2")) << std::endl; << Helper::createFile(test_path("file2.txt")) << std::endl;
std::cout << "Read link of 'file2lnk.txt': " << Helper::readSymlink(test_path("file2lnk.txt")) << std::endl; std::cout << "Create symlink 'file2.txt' to 'file2lnk.txt': "
<< std::boolalpha
<< Helper::createSymlink(test_path("file2.txt"),
test_path("file2lnk.txt"))
<< std::endl;
std::cout << "Size of 'file2.txt': "
<< Helper::fileSize(test_path("file2.txt")) << std::endl;
std::cout << "Erasing 'file.txt': " << std::boolalpha
<< Helper::eraseEntry(test_path("file.txt")) << std::endl;
std::cout << "Erasing 'dir2': " << std::boolalpha
<< Helper::eraseEntry(test_path("dir2")) << std::endl;
std::cout << "Read link of 'file2lnk.txt': "
<< Helper::readSymlink(test_path("file2lnk.txt")) << std::endl;
auto sha256 = Helper::sha256Of(test_path("file2.txt")); auto sha256 = Helper::sha256Of(test_path("file2.txt"));
if (!sha256) if (!sha256) throw Helper::Error("Cannot get sha256 of 'file2.txt'");
throw Helper::Error("Cannot get sha256 of 'file2.txt'"); else std::cout << "SHA256 of 'file2.txt': " << *sha256 << std::endl;
else
std::cout << "SHA256 of 'file2.txt': " << *sha256 << std::endl;
std::cout << "'file2.txt' and 'file2lnk.txt' same? (SHA256): " << std::boolalpha << Helper::sha256Compare(test_path("file2.txt"), test_path("file2lnk.txt")) << std::endl; std::cout << "'file2.txt' and 'file2lnk.txt' same? (SHA256): "
std::cout << "Copy 'file2.txt' as 'file2cpy.txt': " << std::boolalpha << Helper::copyFile(test_path("file2.txt"), test_path("file2cpy.txt")) << std::endl; << std::boolalpha
std::cout << "Run command: 'ls': " << std::boolalpha << Helper::runCommand("ls") << std::endl; << Helper::sha256Compare(test_path("file2.txt"),
std::cout << "Spawn confirm propt..." << std::endl; test_path("file2lnk.txt"))
<< std::endl;
std::cout << "Copy 'file2.txt' as 'file2cpy.txt': " << std::boolalpha
<< Helper::copyFile(test_path("file2.txt"),
test_path("file2cpy.txt"))
<< std::endl;
std::cout << "Run command: 'ls': " << std::boolalpha
<< Helper::runCommand("ls") << std::endl;
std::cout << "Spawn confirm propt..." << std::endl;
bool p = Helper::confirmPropt("Please answer"); bool p = Helper::confirmPropt("Please answer");
std::cout << "Result of confirm propt: " << std::boolalpha << p << std::endl; std::cout << "Result of confirm propt: " << std::boolalpha << p
<< std::endl;
std::cout << "Working directory: " << Helper::currentWorkingDirectory() << std::endl; std::cout << "Working directory: " << Helper::currentWorkingDirectory()
std::cout << "Current date: " << Helper::currentDate() << std::endl; << std::endl;
std::cout << "Current time: " << Helper::currentTime() << std::endl; std::cout << "Current date: " << Helper::currentDate() << std::endl;
std::cout << "Output of 'ls' command: " << Helper::runCommandWithOutput("ls") << std::endl; std::cout << "Current time: " << Helper::currentTime() << std::endl;
std::cout << "Basename of " << test_path("file2.txt") << ": " << Helper::pathBasename(test_path("file2.txt")) << std::endl; std::cout << "Output of 'ls' command: "
std::cout << "Dirname of " << test_path("file2.txt") << ": " << Helper::pathDirname(test_path("file2.txt")) << std::endl; << Helper::runCommandWithOutput("ls") << std::endl;
std::cout << "Basename of " << test_path("file2.txt") << ": "
<< Helper::pathBasename(test_path("file2.txt")) << std::endl;
std::cout << "Dirname of " << test_path("file2.txt") << ": "
<< Helper::pathDirname(test_path("file2.txt")) << std::endl;
std::cout << "pathJoin() test 1: " << Helper::pathJoin("mydir", "dir2") << std::endl; std::cout << "pathJoin() test 1: " << Helper::pathJoin("mydir", "dir2")
std::cout << "pathJoin() test 2: " << Helper::pathJoin("mydir/", "dir2") << std::endl; << std::endl;
std::cout << "pathJoin() test 3: " << Helper::pathJoin("mydir/", "/dir2") << std::endl; std::cout << "pathJoin() test 2: " << Helper::pathJoin("mydir/", "dir2")
std::cout << "pathJoin() test 4: " << Helper::pathJoin("mydir", "/dir2") << std::endl; << std::endl;
std::cout << "pathJoin() test 3: " << Helper::pathJoin("mydir/", "/dir2")
<< std::endl;
std::cout << "pathJoin() test 4: " << Helper::pathJoin("mydir", "/dir2")
<< std::endl;
std::cout << Helper::getLibVersion() << std::endl; std::cout << Helper::getLibVersion() << std::endl;
LOG(INFO) << "Info message" << std::endl; LOG(INFO) << "Info message" << std::endl;
LOG(WARNING) << "Warning message" << std::endl; LOG(WARNING) << "Warning message" << std::endl;
LOG(ERROR) << "Error message" << std::endl; LOG(ERROR) << "Error message" << std::endl;
LOG(ABORT) << "Abort message" << std::endl; LOG(ABORT) << "Abort message" << std::endl;
} catch (Helper::Error& err) { } catch (Helper::Error &err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
return 1; return 1;
} }
return 0; return 0;
} }

500
srclib/libpartition_map/include/libpartition_map/lib.hpp Executable file → Normal file
View File

@@ -17,310 +17,318 @@
#ifndef LIBPARTITION_MAP_LIB_HPP #ifndef LIBPARTITION_MAP_LIB_HPP
#define LIBPARTITION_MAP_LIB_HPP #define LIBPARTITION_MAP_LIB_HPP
#include <cstdint> // for uint64_t
#include <exception>
#include <libhelper/lib.hpp>
#include <list>
#include <memory>
#include <optional>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <optional>
#include <exception>
#include <list>
#include <unordered_map> #include <unordered_map>
#include <memory>
#include <utility> // for std::pair #include <utility> // for std::pair
#include <cstdint> // for uint64_t
#include <libhelper/lib.hpp>
namespace PartitionMap { namespace PartitionMap {
struct _entry { struct _entry {
std::string name; std::string name;
struct { struct {
uint64_t size; uint64_t size;
bool isLogical; bool isLogical;
} props; } props;
}; };
/** /**
* The main type of the library. The Builder class is designed * The main type of the library. The Builder class is designed
* to be easily manipulated and modified only on this class. * to be easily manipulated and modified only on this class.
*/ */
class basic_partition_map final { class basic_partition_map final {
private: private:
void _resize_map(); void _resize_map();
[[nodiscard]] int _index_of(std::string_view name) const; [[nodiscard]] int _index_of(std::string_view name) const;
public: public:
_entry *_data; _entry *_data;
size_t _count{}, _capacity{}; size_t _count{}, _capacity{};
struct _returnable_entry { struct _returnable_entry {
uint64_t size; uint64_t size;
bool isLogical; bool isLogical;
}; };
using BasicInf = _returnable_entry; using BasicInf = _returnable_entry;
basic_partition_map(const std::string &name, uint64_t size, bool logical); basic_partition_map(const std::string &name, uint64_t size, bool logical);
basic_partition_map(const basic_partition_map &other); basic_partition_map(const basic_partition_map &other);
basic_partition_map(); basic_partition_map();
~basic_partition_map(); ~basic_partition_map();
bool insert(const std::string &name, uint64_t size, bool logical); bool insert(const std::string &name, uint64_t size, bool logical);
void merge(const basic_partition_map &map); void merge(const basic_partition_map &map);
void clear(); void clear();
[[nodiscard]] uint64_t get_size(std::string_view name) const; [[nodiscard]] uint64_t get_size(std::string_view name) const;
[[nodiscard]] bool is_logical(std::string_view name) const; [[nodiscard]] bool is_logical(std::string_view name) const;
[[nodiscard]] _returnable_entry get_all(std::string_view name) const; [[nodiscard]] _returnable_entry get_all(std::string_view name) const;
[[nodiscard]] bool find(std::string_view name) const; [[nodiscard]] bool find(std::string_view name) const;
[[nodiscard]] std::string find_(const std::string &name) const; [[nodiscard]] std::string find_(const std::string &name) const;
[[nodiscard]] size_t size() const; [[nodiscard]] size_t size() const;
[[nodiscard]] bool empty() const; [[nodiscard]] bool empty() const;
basic_partition_map &operator=(const basic_partition_map &map); basic_partition_map &operator=(const basic_partition_map &map);
bool operator==(const basic_partition_map &other) const; bool operator==(const basic_partition_map &other) const;
bool operator!=(const basic_partition_map &other) const; bool operator!=(const basic_partition_map &other) const;
class iterator { class iterator {
public: public:
_entry *ptr; _entry *ptr;
explicit iterator(_entry *p); explicit iterator(_entry *p);
auto operator*() const -> std::pair<std::string &, decltype(_entry::props) &>; auto operator*() const
_entry *operator->() const; -> std::pair<std::string &, decltype(_entry::props) &>;
iterator &operator++(); _entry *operator->() const;
iterator operator++(int); iterator &operator++();
bool operator!=(const iterator &other) const; iterator operator++(int);
bool operator==(const iterator &other) const; bool operator!=(const iterator &other) const;
}; bool operator==(const iterator &other) const;
};
class constant_iterator { class constant_iterator {
public: public:
const _entry *ptr; const _entry *ptr;
explicit constant_iterator(const _entry *p); explicit constant_iterator(const _entry *p);
auto operator*() const -> std::pair<const std::string &, const decltype(_entry::props) &>; auto operator*() const
const _entry *operator->() const; -> std::pair<const std::string &, const decltype(_entry::props) &>;
constant_iterator &operator++(); const _entry *operator->() const;
constant_iterator operator++(int); constant_iterator &operator++();
bool operator!=(const constant_iterator &other) const; constant_iterator operator++(int);
bool operator==(const constant_iterator &other) const; bool operator!=(const constant_iterator &other) const;
}; bool operator==(const constant_iterator &other) const;
};
/* for-each support */ /* for-each support */
[[nodiscard]] iterator begin() const; [[nodiscard]] iterator begin() const;
[[nodiscard]] iterator end() const; [[nodiscard]] iterator end() const;
[[nodiscard]] constant_iterator cbegin() const; [[nodiscard]] constant_iterator cbegin() const;
[[nodiscard]] constant_iterator cend() const; [[nodiscard]] constant_iterator cend() const;
}; };
using Map_t = basic_partition_map; using Map_t = basic_partition_map;
class basic_partition_map_builder final { class basic_partition_map_builder final {
private: private:
Map_t _current_map; Map_t _current_map;
std::string _workdir; std::string _workdir;
bool _any_generating_error, _map_builded; bool _any_generating_error, _map_builded;
Map_t _build_map(std::string_view path, bool logical = false); Map_t _build_map(std::string_view path, bool logical = false);
void _insert_logicals(Map_t &&logicals); void _insert_logicals(Map_t &&logicals);
void _map_build_check() const; void _map_build_check() const;
[[nodiscard]] static bool _is_real_block_dir(std::string_view path); [[nodiscard]] static bool _is_real_block_dir(std::string_view path);
[[nodiscard]] uint64_t _get_size(const std::string &path); [[nodiscard]] uint64_t _get_size(const std::string &path);
public: public:
/** /**
* By default, it searches the directories in the * By default, it searches the directories in the
* defaultEntryList in PartitionMap.cpp in order and * defaultEntryList in PartitionMap.cpp in order and
* uses the directory it finds. * uses the directory it finds.
*/ */
basic_partition_map_builder(); basic_partition_map_builder();
/** /**
* A constructor with input. Need search path * A constructor with input. Need search path
*/ */
explicit basic_partition_map_builder(std::string_view path); explicit basic_partition_map_builder(std::string_view path);
/** /**
* Returns the current list content in Map_t type. * Returns the current list content in Map_t type.
* If no list is created, returns std::nullopt. * If no list is created, returns std::nullopt.
*/ */
[[nodiscard]] Map_t getAll() const; [[nodiscard]] Map_t getAll() const;
/** /**
* Returns information of a specific partition in * Returns information of a specific partition in
* Map_temp_t type. If the partition is not in the * Map_temp_t type. If the partition is not in the
* currently created list, returns std::nullopt. * currently created list, returns std::nullopt.
*/ */
[[nodiscard]] std::optional<std::pair<uint64_t, bool> > get(std::string_view name) const; [[nodiscard]] std::optional<std::pair<uint64_t, bool>>
get(std::string_view name) const;
/** /**
* If there is a logical partition(s) in the created * If there is a logical partition(s) in the created
* list, it returns a list of type std::list (containing * list, it returns a list of type std::list (containing
* data of type std::string). If there is no logical * data of type std::string). If there is no logical
* partition in the created list, it returns std::nullopt. * partition in the created list, it returns std::nullopt.
*/ */
[[nodiscard]] std::optional<std::list<std::string> > getLogicalPartitionList() const; [[nodiscard]] std::optional<std::list<std::string>>
getLogicalPartitionList() const;
/** /**
* The physical partitions in the created list are * The physical partitions in the created list are
* returned as std::list type. If there is no content * returned as std::list type. If there is no content
* due to any problem, returns std::nullopt. * due to any problem, returns std::nullopt.
*/ */
[[nodiscard]] std::optional<std::list<std::string> > getPhysicalPartitionList() const; [[nodiscard]] std::optional<std::list<std::string>>
getPhysicalPartitionList() const;
/** /**
* The partitions in the created list are returned as std::list * The partitions in the created list are returned as std::list
* If there is no content due to any problem, returns std::nullopt * If there is no content due to any problem, returns std::nullopt
*/ */
[[nodiscard]] std::optional<std::list<std::string> > getPartitionList() const; [[nodiscard]] std::optional<std::list<std::string>> getPartitionList() const;
/** /**
* Returns the full link path of the entered partition * Returns the full link path of the entered partition
* name in the current search directory as std::string. * name in the current search directory as std::string.
* If the partition is not in the list, an empty * If the partition is not in the list, an empty
* std::string is returned. * std::string is returned.
*/ */
[[nodiscard]] std::string getRealLinkPathOf(std::string_view name) const; [[nodiscard]] std::string getRealLinkPathOf(std::string_view name) const;
/** /**
* Returns the actual path of the partition as * Returns the actual path of the partition as
* std::string. Like /dev/block/sda5 * std::string. Like /dev/block/sda5
*/ */
[[nodiscard]] std::string getRealPathOf(std::string_view name) const; [[nodiscard]] std::string getRealPathOf(std::string_view name) const;
/** /**
* If it exists, the path to the search string is * If it exists, the path to the search string is
* returned as std::string. If it does not exist, * returned as std::string. If it does not exist,
* an empty std::string is returned. * an empty std::string is returned.
*/ */
[[nodiscard]] std::string getCurrentWorkDir() const; [[nodiscard]] std::string getCurrentWorkDir() const;
/** /**
* Returns whether the entered partition name is in the * Returns whether the entered partition name is in the
* created partition list as a bool. * created partition list as a bool.
*/ */
[[nodiscard]] bool hasPartition(std::string_view name) const; [[nodiscard]] bool hasPartition(std::string_view name) const;
/** /**
* Returns the bool type status of whether the * Returns the bool type status of whether the
* entered partition name is marked as logical in the * entered partition name is marked as logical in the
* created list. Alternatively, the current partition * created list. Alternatively, the current partition
* information can be retrieved with the get() function * information can be retrieved with the get() function
* and checked for logicality. * and checked for logicality.
*/ */
[[nodiscard]] bool isLogical(std::string_view name) const; [[nodiscard]] bool isLogical(std::string_view name) const;
/** /**
* The created list and the current search index name are cleared. * The created list and the current search index name are cleared.
*/ */
void clear(); void clear();
/** /**
* The entered path is defined as the new search * The entered path is defined as the new search
* directory and the search is performed in the entered * directory and the search is performed in the entered
* directory. If everything goes well, true is returned. * directory. If everything goes well, true is returned.
*/ */
bool readDirectory(std::string_view path); bool readDirectory(std::string_view path);
/** /**
* Reads default /dev entries and builds map. * Reads default /dev entries and builds map.
*/ */
bool readDefaultDirectories(); bool readDefaultDirectories();
/** /**
* Whether the current list is empty or not is returned * Whether the current list is empty or not is returned
* as bool type. If there is content in the list, true * as bool type. If there is content in the list, true
* is returned, otherwise false is returned. * is returned, otherwise false is returned.
*/ */
[[nodiscard]] bool empty() const; [[nodiscard]] bool empty() const;
/** /**
* If it exists, the size of the partition with the * If it exists, the size of the partition with the
* entered name is returned as uint64_t type. * entered name is returned as uint64_t type.
* If it does not exist, 0 is returned. * If it does not exist, 0 is returned.
*/ */
[[nodiscard]] uint64_t sizeOf(std::string_view name) const; [[nodiscard]] uint64_t sizeOf(std::string_view name) const;
/** /**
* If the content lists of the two created objects are * If the content lists of the two created objects are
* the same (checked only according to the partition * the same (checked only according to the partition
* names), true is returned, otherwise false is returned * names), true is returned, otherwise false is returned
*/ */
friend bool operator==(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs); friend bool operator==(const basic_partition_map_builder &lhs,
const basic_partition_map_builder &rhs);
/** /**
* The opposite logic of the == operator. * The opposite logic of the == operator.
*/ */
friend bool operator!=(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs); friend bool operator!=(const basic_partition_map_builder &lhs,
const basic_partition_map_builder &rhs);
/** /**
* You can check whether the object was created * You can check whether the object was created
* successfully. If the problem did not occur, true is * successfully. If the problem did not occur, true is
* returned, if it did, false is returned. * returned, if it did, false is returned.
*/ */
explicit operator bool() const; explicit operator bool() const;
/** /**
* Returns true if the object creation failed (i.e., there's a problem), * Returns true if the object creation failed (i.e., there's a problem),
* and false if the object is correctly created. * and false if the object is correctly created.
*/ */
bool operator!() const; bool operator!() const;
/** /**
* Build map with input path. Implementation of readDirectory(). * Build map with input path. Implementation of readDirectory().
*/ */
bool operator()(std::string_view path); bool operator()(std::string_view path);
}; };
using Error = Helper::Error; using Error = Helper::Error;
/** /**
* To get the version information of libpartition_map * To get the version information of libpartition_map
* library. It is returned as std::string type. * library. It is returned as std::string type.
*/ */
std::string getLibVersion(); std::string getLibVersion();
using BuildMap = basic_partition_map_builder; using BuildMap = basic_partition_map_builder;
using Map = basic_partition_map_builder; using Map = basic_partition_map_builder;
namespace Extras { namespace Extras {
namespace FileSystemMagic { namespace FileSystemMagic {
constexpr uint64_t EXTFS_FS = 0xEF53; constexpr uint64_t EXTFS_FS = 0xEF53;
constexpr uint64_t F2FS_FS = 0xF2F52010; constexpr uint64_t F2FS_FS = 0xF2F52010;
constexpr uint64_t EROFS_FS = 0xE0F5E1E2; constexpr uint64_t EROFS_FS = 0xE0F5E1E2;
constexpr uint64_t EXFAT_FS = 0x5441465845; constexpr uint64_t EXFAT_FS = 0x5441465845;
constexpr uint64_t FAT12_FS = 0x3231544146; constexpr uint64_t FAT12_FS = 0x3231544146;
constexpr uint64_t FAT16_FS = 0x3631544146; constexpr uint64_t FAT16_FS = 0x3631544146;
constexpr uint64_t FAT32_FS = 0x3233544146; constexpr uint64_t FAT32_FS = 0x3233544146;
constexpr uint64_t NTFS_FS = 0x5346544E; constexpr uint64_t NTFS_FS = 0x5346544E;
constexpr uint64_t MSDOS_FS = 0x4d44; constexpr uint64_t MSDOS_FS = 0x4d44;
} // namespace FileSystemMagic } // namespace FileSystemMagic
namespace AndroidMagic { namespace AndroidMagic {
constexpr uint64_t BOOT_IMAGE = 0x2144494F52444E41; constexpr uint64_t BOOT_IMAGE = 0x2144494F52444E41;
constexpr uint64_t VBOOT_IMAGE = 0x544F4F4252444E56; constexpr uint64_t VBOOT_IMAGE = 0x544F4F4252444E56;
constexpr uint64_t LK_IMAGE = 0x00006B6C; constexpr uint64_t LK_IMAGE = 0x00006B6C;
constexpr uint64_t DTBO_IMAGE = 0x1EABB7D7; constexpr uint64_t DTBO_IMAGE = 0x1EABB7D7;
constexpr uint64_t VBMETA_IMAGE = 0x425641; constexpr uint64_t VBMETA_IMAGE = 0x425641;
constexpr uint64_t SUPER_IMAGE = 0x7265797573; constexpr uint64_t SUPER_IMAGE = 0x7265797573;
constexpr uint64_t SPARSE_IMAGE = 0x3AFF26ED; constexpr uint64_t SPARSE_IMAGE = 0x3AFF26ED;
constexpr uint64_t ELF = 0x464C457F; // It makes more sense than between file systems constexpr uint64_t ELF =
constexpr uint64_t RAW = 0x00000000; 0x464C457F; // It makes more sense than between file systems
} // namespace AndroidMagic constexpr uint64_t RAW = 0x00000000;
} // namespace AndroidMagic
extern std::unordered_map<uint64_t, std::string> FileSystemMagicMap; extern std::unordered_map<uint64_t, std::string> FileSystemMagicMap;
extern std::unordered_map<uint64_t, std::string> AndroidMagicMap; extern std::unordered_map<uint64_t, std::string> AndroidMagicMap;
extern std::unordered_map<uint64_t, std::string> MagicMap; extern std::unordered_map<uint64_t, std::string> MagicMap;
size_t getMagicLength(uint64_t magic); size_t getMagicLength(uint64_t magic);
bool hasMagic(uint64_t magic, ssize_t buf, const std::string &path); bool hasMagic(uint64_t magic, ssize_t buf, const std::string &path);
std::string formatMagic(uint64_t magic); std::string formatMagic(uint64_t magic);
} // namespace Extras } // namespace Extras
} // namespace PartitionMap } // namespace PartitionMap
#define MAP "libpartition_map" #define MAP "libpartition_map"

110
srclib/libpartition_map/src/Getters.cpp Executable file → Normal file
View File

@@ -14,77 +14,83 @@
limitations under the License. limitations under the License.
*/ */
#include <string>
#include <optional>
#include <filesystem> #include <filesystem>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
#include <optional>
#include <string>
namespace PartitionMap { namespace PartitionMap {
Map_t basic_partition_map_builder::getAll() const { Map_t basic_partition_map_builder::getAll() const {
_map_build_check(); _map_build_check();
return _current_map; return _current_map;
} }
std::optional<std::pair<uint64_t, bool> > basic_partition_map_builder::get(const std::string_view name) const { std::optional<std::pair<uint64_t, bool>>
_map_build_check(); basic_partition_map_builder::get(const std::string_view name) const {
_map_build_check();
if (!_current_map.find(name)) return std::nullopt; if (!_current_map.find(name)) return std::nullopt;
return std::make_pair(_current_map.get_size(name), _current_map.is_logical(name)); return std::make_pair(_current_map.get_size(name),
} _current_map.is_logical(name));
}
std::optional<std::list<std::string> > basic_partition_map_builder::getLogicalPartitionList() const { std::optional<std::list<std::string>>
_map_build_check(); basic_partition_map_builder::getLogicalPartitionList() const {
_map_build_check();
std::list<std::string> logicals; std::list<std::string> logicals;
for (const auto &[name, props]: _current_map) for (const auto &[name, props] : _current_map)
if (props.isLogical) logicals.push_back(name); if (props.isLogical) logicals.push_back(name);
if (logicals.empty()) return std::nullopt; if (logicals.empty()) return std::nullopt;
return logicals; return logicals;
} }
std::optional<std::list<std::string> > basic_partition_map_builder::getPhysicalPartitionList() const { std::optional<std::list<std::string>>
_map_build_check(); basic_partition_map_builder::getPhysicalPartitionList() const {
_map_build_check();
std::list<std::string> physicals; std::list<std::string> physicals;
for (const auto &[name, props]: _current_map) for (const auto &[name, props] : _current_map)
if (!props.isLogical) physicals.push_back(name); if (!props.isLogical) physicals.push_back(name);
if (physicals.empty()) return std::nullopt; if (physicals.empty()) return std::nullopt;
return physicals; return physicals;
} }
std::optional<std::list<std::string> > basic_partition_map_builder::getPartitionList() const { std::optional<std::list<std::string>>
_map_build_check(); basic_partition_map_builder::getPartitionList() const {
_map_build_check();
std::list<std::string> partitions; std::list<std::string> partitions;
for (const auto &[name, props]: _current_map) partitions.push_back(name); for (const auto &[name, props] : _current_map)
partitions.push_back(name);
if (partitions.empty()) return std::nullopt; if (partitions.empty()) return std::nullopt;
return partitions; return partitions;
} }
std::string basic_partition_map_builder::getRealLinkPathOf(const std::string_view name) const { std::string basic_partition_map_builder::getRealLinkPathOf(
_map_build_check(); const std::string_view name) const {
_map_build_check();
if (!_current_map.find(name)) return {}; if (!_current_map.find(name)) return {};
return std::string(_workdir + "/" + name.data()); return std::string(_workdir + "/" + name.data());
} }
std::string basic_partition_map_builder::getRealPathOf(const std::string_view name) const { std::string
_map_build_check(); basic_partition_map_builder::getRealPathOf(const std::string_view name) const {
_map_build_check();
const std::string full = (isLogical(name)) const std::string full = (isLogical(name))
? std::string("/dev/block/mapper/") + name.data() ? std::string("/dev/block/mapper/") + name.data()
: _workdir + "/" + name.data(); : _workdir + "/" + name.data();
if (!_current_map.find(name) if (!_current_map.find(name) || !std::filesystem::is_symlink(full)) return {};
|| !std::filesystem::is_symlink(full))
return {};
return std::filesystem::read_symlink(full); return std::filesystem::read_symlink(full);
} }
std::string basic_partition_map_builder::getCurrentWorkDir() const { std::string basic_partition_map_builder::getCurrentWorkDir() const {
return _workdir; return _workdir;
} }
} // namespace PartitionMap } // namespace PartitionMap

View File

@@ -5,7 +5,7 @@
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,105 +15,109 @@
*/ */
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
#include <sstream>
#include <string>
#include <unordered_map>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
#include <sstream>
#include <string>
#include <unistd.h>
#include <unordered_map>
#include "PartitionManager/PartitionManager.hpp" #include "PartitionManager/PartitionManager.hpp"
namespace PartitionMap::Extras { namespace PartitionMap::Extras {
std::unordered_map<uint64_t, std::string> FileSystemMagicMap = { std::unordered_map<uint64_t, std::string> FileSystemMagicMap = {
{FileSystemMagic::EXTFS_FS, "EXT2/3/4"}, {FileSystemMagic::EXTFS_FS, "EXT2/3/4"},
{FileSystemMagic::F2FS_FS, "F2FS"}, {FileSystemMagic::F2FS_FS, "F2FS"},
{FileSystemMagic::EROFS_FS, "EROFS"}, {FileSystemMagic::EROFS_FS, "EROFS"},
{FileSystemMagic::EXFAT_FS, "exFAT"}, {FileSystemMagic::EXFAT_FS, "exFAT"},
{FileSystemMagic::FAT12_FS, "FAT12"}, {FileSystemMagic::FAT12_FS, "FAT12"},
{FileSystemMagic::FAT16_FS, "FAT16"}, {FileSystemMagic::FAT16_FS, "FAT16"},
{FileSystemMagic::FAT32_FS, "FAT32"}, {FileSystemMagic::FAT32_FS, "FAT32"},
{FileSystemMagic::NTFS_FS, "NTFS"}, {FileSystemMagic::NTFS_FS, "NTFS"},
{FileSystemMagic::MSDOS_FS, "MSDOS"} {FileSystemMagic::MSDOS_FS, "MSDOS"}};
};
std::unordered_map<uint64_t, std::string> AndroidMagicMap = { std::unordered_map<uint64_t, std::string> AndroidMagicMap = {
{AndroidMagic::BOOT_IMAGE, "Android Boot Image"}, {AndroidMagic::BOOT_IMAGE, "Android Boot Image"},
{AndroidMagic::VBOOT_IMAGE, "Android Vendor Boot Image"}, {AndroidMagic::VBOOT_IMAGE, "Android Vendor Boot Image"},
{AndroidMagic::LK_IMAGE, "Android LK (Bootloader)"}, {AndroidMagic::LK_IMAGE, "Android LK (Bootloader)"},
{AndroidMagic::DTBO_IMAGE, "Android DTBO Image"}, {AndroidMagic::DTBO_IMAGE, "Android DTBO Image"},
{AndroidMagic::VBMETA_IMAGE, "Android VBMeta Image"}, {AndroidMagic::VBMETA_IMAGE, "Android VBMeta Image"},
{AndroidMagic::SUPER_IMAGE, "Android Super Image"}, {AndroidMagic::SUPER_IMAGE, "Android Super Image"},
{AndroidMagic::SPARSE_IMAGE, "Android Sparse Image"}, {AndroidMagic::SPARSE_IMAGE, "Android Sparse Image"},
{AndroidMagic::ELF, "ELF"}, {AndroidMagic::ELF, "ELF"},
{AndroidMagic::RAW, "Raw Data"} {AndroidMagic::RAW, "Raw Data"}};
};
std::unordered_map<uint64_t, std::string> MagicMap = { std::unordered_map<uint64_t, std::string> MagicMap = {
{AndroidMagic::BOOT_IMAGE, "Android Boot Image"}, {AndroidMagic::BOOT_IMAGE, "Android Boot Image"},
{AndroidMagic::VBOOT_IMAGE, "Android Vendor Boot Image"}, {AndroidMagic::VBOOT_IMAGE, "Android Vendor Boot Image"},
{AndroidMagic::LK_IMAGE, "Android LK (Bootloader)"}, {AndroidMagic::LK_IMAGE, "Android LK (Bootloader)"},
{AndroidMagic::DTBO_IMAGE, "Android DTBO Image"}, {AndroidMagic::DTBO_IMAGE, "Android DTBO Image"},
{AndroidMagic::VBMETA_IMAGE, "Android VBMeta Image"}, {AndroidMagic::VBMETA_IMAGE, "Android VBMeta Image"},
{AndroidMagic::SUPER_IMAGE, "Android Super Image"}, {AndroidMagic::SUPER_IMAGE, "Android Super Image"},
{AndroidMagic::SPARSE_IMAGE, "Android Sparse Image"}, {AndroidMagic::SPARSE_IMAGE, "Android Sparse Image"},
{AndroidMagic::ELF, "ELF"}, {AndroidMagic::ELF, "ELF"},
{AndroidMagic::RAW, "Raw Data"}, {AndroidMagic::RAW, "Raw Data"},
{FileSystemMagic::EXTFS_FS, "EXT2/3/4"}, {FileSystemMagic::EXTFS_FS, "EXT2/3/4"},
{FileSystemMagic::F2FS_FS, "F2FS"}, {FileSystemMagic::F2FS_FS, "F2FS"},
{FileSystemMagic::EROFS_FS, "EROFS"}, {FileSystemMagic::EROFS_FS, "EROFS"},
{FileSystemMagic::EXFAT_FS, "exFAT"}, {FileSystemMagic::EXFAT_FS, "exFAT"},
{FileSystemMagic::FAT12_FS, "FAT12"}, {FileSystemMagic::FAT12_FS, "FAT12"},
{FileSystemMagic::FAT16_FS, "FAT16"}, {FileSystemMagic::FAT16_FS, "FAT16"},
{FileSystemMagic::FAT32_FS, "FAT32"}, {FileSystemMagic::FAT32_FS, "FAT32"},
{FileSystemMagic::NTFS_FS, "NTFS"}, {FileSystemMagic::NTFS_FS, "NTFS"},
{FileSystemMagic::MSDOS_FS, "MSDOS"} {FileSystemMagic::MSDOS_FS, "MSDOS"}};
};
size_t getMagicLength(const uint64_t magic) { size_t getMagicLength(const uint64_t magic) {
size_t length = 0; size_t length = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
if ((magic >> (8 * i)) & 0xFF) length = i + 1; if ((magic >> (8 * i)) & 0xFF) length = i + 1;
} }
return length; return length;
} }
bool hasMagic(const uint64_t magic, const ssize_t buf, const std::string &path) { bool hasMagic(const uint64_t magic, const ssize_t buf,
LOGN(MAP, INFO) << "Checking magic of " << path << " with using " << buf << " byte buffer size (has magic 0x" << std::hex << magic << "?)" << std::endl; const std::string &path) {
Helper::garbageCollector collector; LOGN(MAP, INFO) << "Checking magic of " << path << " with using " << buf
<< " byte buffer size (has magic 0x" << std::hex << magic
<< "?)" << std::endl;
Helper::garbageCollector collector;
const int fd = Helper::openAndAddToCloseList(path, collector, O_RDONLY); const int fd = Helper::openAndAddToCloseList(path, collector, O_RDONLY);
if (fd < 0) return false; if (fd < 0) return false;
if (buf < 1) { if (buf < 1) {
LOGN(MAP, ERROR) << "Buffer size is older than 1" << std::endl; LOGN(MAP, ERROR) << "Buffer size is older than 1" << std::endl;
return false; return false;
} }
auto *buffer = new uint8_t[buf]; auto *buffer = new uint8_t[buf];
collector.delAfterProgress(buffer); collector.delAfterProgress(buffer);
const ssize_t bytesRead = read(fd, buffer, buf); const ssize_t bytesRead = read(fd, buffer, buf);
if (bytesRead < 0) return false; if (bytesRead < 0) return false;
const size_t magicLength = getMagicLength(magic); const size_t magicLength = getMagicLength(magic);
if (magicLength == 0) return false; if (magicLength == 0) return false;
for (size_t i = 0; i <= bytesRead - magicLength; i++) { for (size_t i = 0; i <= bytesRead - magicLength; i++) {
uint64_t value = 0; uint64_t value = 0;
for (size_t j = 0; j < magicLength; ++j) value |= static_cast<uint64_t>(buffer[i + j]) << (8 * j); for (size_t j = 0; j < magicLength; ++j)
if (value == magic) { value |= static_cast<uint64_t>(buffer[i + j]) << (8 * j);
LOGN(MAP, INFO) << path << " contains 0x" << std::hex << magic << std::endl; if (value == magic) {
return true; LOGN(MAP, INFO) << path << " contains 0x" << std::hex << magic
} << std::endl;
} return true;
}
}
LOGN(MAP, INFO) << path << " is not contains 0x" << std::hex << magic << std::endl; LOGN(MAP, INFO) << path << " is not contains 0x" << std::hex << magic
return false; << std::endl;
} return false;
}
std::string formatMagic(const uint64_t magic) { std::string formatMagic(const uint64_t magic) {
std::stringstream ss; std::stringstream ss;
ss << "0x" << std::uppercase << std::hex << std::setw(16) << std::setfill('0') << magic; ss << "0x" << std::uppercase << std::hex << std::setw(16) << std::setfill('0')
return ss.str(); << magic;
} return ss.str();
}
} // namespace PartitionMap::Extras } // namespace PartitionMap::Extras

368
srclib/libpartition_map/src/PartitionMap.cpp Executable file → Normal file
View File

@@ -14,222 +14,242 @@
limitations under the License. limitations under the License.
*/ */
#include <iostream>
#include <vector>
#include <filesystem>
#include <memory>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cerrno>
#include <cstring>
#include <fcntl.h>
#include <filesystem>
#include <generated/buildInfo.hpp>
#include <iostream>
#include <libpartition_map/lib.hpp>
#include <linux/fs.h>
#include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <cerrno>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/fs.h> #include <sys/stat.h>
#include <libpartition_map/lib.hpp>
#include <generated/buildInfo.hpp>
#include <cstring>
#include <unistd.h> #include <unistd.h>
#include <vector>
static constexpr std::array<std::string_view, 3> defaultEntryList = { static constexpr std::array<std::string_view, 3> defaultEntryList = {
"/dev/block/by-name", "/dev/block/by-name", "/dev/block/bootdevice/by-name",
"/dev/block/bootdevice/by-name", "/dev/block/platform/bootdevice/by-name"};
"/dev/block/platform/bootdevice/by-name"
};
namespace PartitionMap { namespace PartitionMap {
bool basic_partition_map_builder::_is_real_block_dir(const std::string_view path) { bool basic_partition_map_builder::_is_real_block_dir(
if (path.find("/block/") == std::string::npos) { const std::string_view path) {
LOGN(MAP, ERROR) << "Path " << path << " is not a real block directory."; if (path.find("/block/") == std::string::npos) {
return false; LOGN(MAP, ERROR) << "Path " << path << " is not a real block directory.";
} return false;
return true; }
} return true;
}
Map_t basic_partition_map_builder::_build_map(std::string_view path, bool logical) { Map_t basic_partition_map_builder::_build_map(std::string_view path,
Map_t map; bool logical) {
std::vector<std::filesystem::directory_entry> entries{ Map_t map;
std::filesystem::directory_iterator(path), std::filesystem::directory_iterator() std::vector<std::filesystem::directory_entry> entries{
}; std::filesystem::directory_iterator(path),
std::sort(entries.begin(), entries.end(), [](const auto &a, const auto &b) { std::filesystem::directory_iterator()};
return a.path().filename() < b.path().filename(); std::sort(entries.begin(), entries.end(), [](const auto &a, const auto &b) {
}); return a.path().filename() < b.path().filename();
});
LOGN_IF(MAP, WARNING, entries.empty()) << "" << path << LOGN_IF(MAP, WARNING, entries.empty())
"is exists but generated vector is empty (std::vector<std::filesystem::directory_entry>)." << std::endl; << "" << path
for (const auto &entry: entries) { << "is exists but generated vector is empty "
if (entry.path().filename() != "by-uuid" "(std::vector<std::filesystem::directory_entry>)."
&& std::string(entry.path()).find("com.") == std::string::npos) << std::endl;
map.insert(entry.path().filename().string(), _get_size(entry.path()), logical); for (const auto &entry : entries) {
} if (entry.path().filename() != "by-uuid" &&
std::string(entry.path()).find("com.") == std::string::npos)
map.insert(entry.path().filename().string(), _get_size(entry.path()),
logical);
}
LOGN(MAP, INFO) << std::boolalpha << "Map generated successfully. is_logical_map=" << logical << std::endl; LOGN(MAP, INFO) << std::boolalpha
return map; << "Map generated successfully. is_logical_map=" << logical
} << std::endl;
return map;
}
void basic_partition_map_builder::_insert_logicals(Map_t &&logicals) { void basic_partition_map_builder::_insert_logicals(Map_t &&logicals) {
LOGN(MAP, INFO) << "merging created logical partition list to this object's variable." << std::endl; LOGN(MAP, INFO)
_current_map.merge(logicals); << "merging created logical partition list to this object's variable."
} << std::endl;
_current_map.merge(logicals);
}
void basic_partition_map_builder::_map_build_check() const { void basic_partition_map_builder::_map_build_check() const {
if (!_map_builded) if (!_map_builded) throw Error("Please build partition map before!");
throw Error("Please build partition map before!"); }
}
uint64_t basic_partition_map_builder::_get_size(const std::string &path) { uint64_t basic_partition_map_builder::_get_size(const std::string &path) {
const std::string real = std::filesystem::read_symlink(path); const std::string real = std::filesystem::read_symlink(path);
Helper::garbageCollector collector; Helper::garbageCollector collector;
const int fd = Helper::openAndAddToCloseList(real, collector, O_RDONLY); const int fd = Helper::openAndAddToCloseList(real, collector, O_RDONLY);
if (fd < 0) { if (fd < 0) {
LOGN(MAP, ERROR) << "Cannot open " << real << ": " << strerror(errno) << std::endl; LOGN(MAP, ERROR) << "Cannot open " << real << ": " << strerror(errno)
return 0; << std::endl;
} return 0;
}
uint64_t size = 0; uint64_t size = 0;
if (ioctl(fd, BLKGETSIZE64, &size) != 0) { if (ioctl(fd, BLKGETSIZE64, &size) != 0) {
LOGN(MAP, ERROR) << "ioctl() process failed for " << real << ": " << strerror(errno) << std::endl; LOGN(MAP, ERROR) << "ioctl() process failed for " << real << ": "
return 0; << strerror(errno) << std::endl;
} return 0;
}
return size; return size;
} }
basic_partition_map_builder::basic_partition_map_builder() { basic_partition_map_builder::basic_partition_map_builder() {
LOGN(MAP, INFO) << "default constructor called. Starting build." << std::endl; LOGN(MAP, INFO) << "default constructor called. Starting build." << std::endl;
for (const auto &path: defaultEntryList) { for (const auto &path : defaultEntryList) {
if (std::filesystem::exists(path)) { if (std::filesystem::exists(path)) {
_current_map = _build_map(path); _current_map = _build_map(path);
if (_current_map.empty()) { if (_current_map.empty()) {
_any_generating_error = true; _any_generating_error = true;
} else { } else {
_workdir = path; _workdir = path;
break; break;
} }
} }
} }
if (_current_map.empty()) if (_current_map.empty())
LOGN(MAP, ERROR) << "Cannot build map by any default search entry." << std::endl; LOGN(MAP, ERROR) << "Cannot build map by any default search entry."
<< std::endl;
LOGN(MAP, INFO) << "default constructor successfully ended work." << std::endl; LOGN(MAP, INFO) << "default constructor successfully ended work."
_insert_logicals(_build_map("/dev/block/mapper", true)); << std::endl;
_map_builded = true; _insert_logicals(_build_map("/dev/block/mapper", true));
} _map_builded = true;
}
basic_partition_map_builder::basic_partition_map_builder(const std::string_view path) { basic_partition_map_builder::basic_partition_map_builder(
LOGN(MAP, INFO) << "argument-based constructor called. Starting build." << std::endl; const std::string_view path) {
LOGN(MAP, INFO) << "argument-based constructor called. Starting build."
<< std::endl;
if (std::filesystem::exists(path)) { if (std::filesystem::exists(path)) {
if (!_is_real_block_dir(path)) return; if (!_is_real_block_dir(path)) return;
_current_map = _build_map(path); _current_map = _build_map(path);
if (_current_map.empty()) _any_generating_error = true; if (_current_map.empty()) _any_generating_error = true;
else _workdir = path; else _workdir = path;
} else } else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data()); throw Error("Cannot find directory: %s. Cannot build partition map!",
path.data());
LOGN(MAP, INFO) << "argument-based constructor successfully ended work." << std::endl; LOGN(MAP, INFO) << "argument-based constructor successfully ended work."
_insert_logicals(_build_map("/dev/block/mapper", true)); << std::endl;
_map_builded = true; _insert_logicals(_build_map("/dev/block/mapper", true));
} _map_builded = true;
}
bool basic_partition_map_builder::hasPartition(const std::string_view name) const { bool basic_partition_map_builder::hasPartition(
_map_build_check(); const std::string_view name) const {
return _current_map.find(name); _map_build_check();
} return _current_map.find(name);
}
bool basic_partition_map_builder::isLogical(const std::string_view name) const { bool basic_partition_map_builder::isLogical(const std::string_view name) const {
_map_build_check(); _map_build_check();
return _current_map.is_logical(name); return _current_map.is_logical(name);
} }
void basic_partition_map_builder::clear() { void basic_partition_map_builder::clear() {
_current_map.clear(); _current_map.clear();
_workdir.clear(); _workdir.clear();
_any_generating_error = false; _any_generating_error = false;
} }
bool basic_partition_map_builder::readDirectory(const std::string_view path) { bool basic_partition_map_builder::readDirectory(const std::string_view path) {
_map_builded = false; _map_builded = false;
LOGN(MAP, INFO) << "read " << path << " directory request." << std::endl; LOGN(MAP, INFO) << "read " << path << " directory request." << std::endl;
if (std::filesystem::exists(path)) { if (std::filesystem::exists(path)) {
if (!_is_real_block_dir(path)) return false; if (!_is_real_block_dir(path)) return false;
_current_map = _build_map(path); _current_map = _build_map(path);
if (_current_map.empty()) { if (_current_map.empty()) {
_any_generating_error = true; _any_generating_error = true;
return false; return false;
} else _workdir = path; } else _workdir = path;
} else } else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data()); throw Error("Cannot find directory: %s. Cannot build partition map!",
path.data());
LOGN(MAP, INFO) << "read " << path << " successfull." << std::endl; LOGN(MAP, INFO) << "read " << path << " successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true)); _insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true; _map_builded = true;
return true; return true;
} }
bool basic_partition_map_builder::readDefaultDirectories() { bool basic_partition_map_builder::readDefaultDirectories() {
_map_builded = false; _map_builded = false;
LOGN(MAP, INFO) << "read default directories request." << std::endl; LOGN(MAP, INFO) << "read default directories request." << std::endl;
for (const auto &path: defaultEntryList) { for (const auto &path : defaultEntryList) {
if (std::filesystem::exists(path)) { if (std::filesystem::exists(path)) {
_current_map = _build_map(path); _current_map = _build_map(path);
if (_current_map.empty()) { if (_current_map.empty()) {
_any_generating_error = true; _any_generating_error = true;
return false; return false;
} else { } else {
_workdir = path; _workdir = path;
break; break;
} }
} }
} }
if (_current_map.empty()) if (_current_map.empty())
LOGN(MAP, ERROR) << "Cannot build map by any default search entry." << std::endl; LOGN(MAP, ERROR) << "Cannot build map by any default search entry."
<< std::endl;
LOGN(MAP, INFO) << "read default directories successfull." << std::endl; LOGN(MAP, INFO) << "read default directories successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true)); _insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true; _map_builded = true;
return true; return true;
} }
bool basic_partition_map_builder::empty() const { bool basic_partition_map_builder::empty() const {
_map_build_check(); _map_build_check();
return _current_map.empty(); return _current_map.empty();
} }
uint64_t basic_partition_map_builder::sizeOf(const std::string_view name) const { uint64_t
_map_build_check(); basic_partition_map_builder::sizeOf(const std::string_view name) const {
return _current_map.get_size(name); _map_build_check();
} return _current_map.get_size(name);
}
bool operator==(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs) { bool operator==(const basic_partition_map_builder &lhs,
return lhs._current_map == rhs._current_map; const basic_partition_map_builder &rhs) {
} return lhs._current_map == rhs._current_map;
}
bool operator!=(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs) { bool operator!=(const basic_partition_map_builder &lhs,
return !(lhs == rhs); const basic_partition_map_builder &rhs) {
} return !(lhs == rhs);
}
basic_partition_map_builder::operator bool() const { basic_partition_map_builder::operator bool() const {
return !this->_any_generating_error; return !this->_any_generating_error;
} }
bool basic_partition_map_builder::operator!() const { bool basic_partition_map_builder::operator!() const {
return this->_any_generating_error; return this->_any_generating_error;
} }
bool basic_partition_map_builder::operator()(const std::string_view path) { bool basic_partition_map_builder::operator()(const std::string_view path) {
LOGN(MAP, INFO) << "calling readDirectory() for building map with " << path << std::endl; LOGN(MAP, INFO) << "calling readDirectory() for building map with " << path
return readDirectory(path); << std::endl;
} return readDirectory(path);
}
std::string getLibVersion() { std::string getLibVersion() { MKVERSION("libpartition_map"); }
MKVERSION("libpartition_map");
}
} // namespace PartitionMap } // namespace PartitionMap

336
srclib/libpartition_map/src/Type.cpp Executable file → Normal file
View File

@@ -14,223 +14,227 @@
limitations under the License. limitations under the License.
*/ */
#include <string>
#include <cstdint> #include <cstdint>
#include <utility>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
#include <string>
#include <utility>
namespace PartitionMap { namespace PartitionMap {
basic_partition_map::iterator::iterator(_entry *p) : ptr(p) { basic_partition_map::iterator::iterator(_entry *p) : ptr(p) {}
}
auto basic_partition_map::iterator::operator*() const -> std::pair<std::string &, decltype(_entry::props) &> { auto basic_partition_map::iterator::operator*() const
return {ptr->name, ptr->props}; -> std::pair<std::string &, decltype(_entry::props) &> {
} return {ptr->name, ptr->props};
}
_entry *basic_partition_map::iterator::operator->() const { _entry *basic_partition_map::iterator::operator->() const { return ptr; }
return ptr;
}
basic_partition_map::iterator &basic_partition_map::iterator::operator++() { basic_partition_map::iterator &basic_partition_map::iterator::operator++() {
++ptr; ++ptr;
return *this; return *this;
} }
basic_partition_map::iterator basic_partition_map::iterator::operator++(int) { basic_partition_map::iterator basic_partition_map::iterator::operator++(int) {
iterator tmp = *this; iterator tmp = *this;
++ptr; ++ptr;
return tmp; return tmp;
} }
bool basic_partition_map::iterator::operator==(const iterator &other) const { bool basic_partition_map::iterator::operator==(const iterator &other) const {
return ptr == other.ptr; return ptr == other.ptr;
} }
bool basic_partition_map::iterator::operator!=(const iterator &other) const { bool basic_partition_map::iterator::operator!=(const iterator &other) const {
return ptr != other.ptr; return ptr != other.ptr;
} }
basic_partition_map::constant_iterator::constant_iterator(const _entry *p) : ptr(p) { basic_partition_map::constant_iterator::constant_iterator(const _entry *p)
} : ptr(p) {}
auto basic_partition_map::constant_iterator::operator auto basic_partition_map::constant_iterator::operator*() const
*() const -> std::pair<const std::string &, const decltype(_entry::props) &> { -> std::pair<const std::string &, const decltype(_entry::props) &> {
return {ptr->name, ptr->props}; return {ptr->name, ptr->props};
} }
const _entry *basic_partition_map::constant_iterator::operator->() const {
return ptr;
}
const _entry *basic_partition_map::constant_iterator::operator->() const { basic_partition_map::constant_iterator &
return ptr; basic_partition_map::constant_iterator::operator++() {
} ++ptr;
return *this;
}
basic_partition_map::constant_iterator &basic_partition_map::constant_iterator::operator++() { basic_partition_map::constant_iterator
++ptr; basic_partition_map::constant_iterator::operator++(int) {
return *this; constant_iterator tmp = *this;
} ++ptr;
return tmp;
}
basic_partition_map::constant_iterator basic_partition_map::constant_iterator::operator++(int) { bool basic_partition_map::constant_iterator::operator==(
constant_iterator tmp = *this; const constant_iterator &other) const {
++ptr; return ptr == other.ptr;
return tmp; }
}
bool basic_partition_map::constant_iterator::operator==(const constant_iterator &other) const { bool basic_partition_map::constant_iterator::operator!=(
return ptr == other.ptr; const constant_iterator &other) const {
} return ptr != other.ptr;
}
bool basic_partition_map::constant_iterator::operator!=(const constant_iterator &other) const { void basic_partition_map::_resize_map() {
return ptr != other.ptr; const size_t new_capacity = _capacity * 2;
} auto *new_data = new _entry[new_capacity];
void basic_partition_map::_resize_map() { for (size_t i = 0; i < _count; i++)
const size_t new_capacity = _capacity * 2; new_data[i] = _data[i];
auto *new_data = new _entry[new_capacity];
for (size_t i = 0; i < _count; i++) new_data[i] = _data[i]; delete[] _data;
_data = new_data;
_capacity = new_capacity;
}
delete[] _data; int basic_partition_map::_index_of(const std::string_view name) const {
_data = new_data; for (size_t i = 0; i < _count; i++) {
_capacity = new_capacity; if (name == _data[i].name) return static_cast<int>(i);
} }
int basic_partition_map::_index_of(const std::string_view name) const { return 0;
for (size_t i = 0; i < _count; i++) { }
if (name == _data[i].name) return static_cast<int>(i);
}
return 0; basic_partition_map::basic_partition_map(const std::string &name,
} const uint64_t size,
const bool logical) {
_data = new _entry[_capacity];
insert(name, size, logical);
}
basic_partition_map::basic_partition_map(const std::string &name, const uint64_t size, const bool logical) { basic_partition_map::basic_partition_map(const basic_partition_map &other)
_data = new _entry[_capacity]; : _data(new _entry[other._capacity]), _count(other._count),
insert(name, size, logical); _capacity(other._capacity) {
} std::copy(other._data, other._data + _count, _data);
}
basic_partition_map::basic_partition_map(const basic_partition_map &other) : _data(new _entry[other._capacity]), basic_partition_map::basic_partition_map() : _capacity(6) {
_count(other._count), _data = new _entry[_capacity];
_capacity(other._capacity) { }
std::copy(other._data, other._data + _count, _data);
}
basic_partition_map::basic_partition_map() : _capacity(6) { basic_partition_map::~basic_partition_map() { delete[] _data; }
_data = new _entry[_capacity];
}
basic_partition_map::~basic_partition_map() { bool basic_partition_map::insert(const std::string &name, const uint64_t size,
delete[] _data; const bool logical) {
} if (name == _data[_index_of(name)].name) return false;
if (_count == _capacity) _resize_map();
bool basic_partition_map::insert(const std::string &name, const uint64_t size, const bool logical) { _data[_count++] = {name, {size, logical}};
if (name == _data[_index_of(name)].name) return false; LOGN(MAP, INFO) << std::boolalpha << "partition " << name
if (_count == _capacity) _resize_map(); << " inserted (size=" << size << ", is_logical=" << logical
<< ")." << std::endl;
return true;
}
_data[_count++] = {name, {size, logical}}; void basic_partition_map::merge(const basic_partition_map &map) {
LOGN(MAP, INFO) << std::boolalpha << "partition " << name << " inserted (size=" << size << ", is_logical=" << LOGN(MAP, INFO) << "map merge request." << std::endl;
logical << ")." << std::endl; for (const auto &[name, props] : map)
return true; insert(name, props.size, props.isLogical);
} LOGN(MAP, INFO) << "map merged successfully." << std::endl;
}
void basic_partition_map::merge(const basic_partition_map &map) { uint64_t basic_partition_map::get_size(const std::string_view name) const {
LOGN(MAP, INFO) << "map merge request." << std::endl; if (const int pos = _index_of(name); name == _data[pos].name)
for (const auto &[name, props]: map) return _data[pos].props.size;
insert(name, props.size, props.isLogical);
LOGN(MAP, INFO) << "map merged successfully." << std::endl;
}
uint64_t basic_partition_map::get_size(const std::string_view name) const { return 0;
if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.size; }
return 0; bool basic_partition_map::is_logical(const std::string_view name) const {
} if (const int pos = _index_of(name); name == _data[pos].name)
return _data[pos].props.isLogical;
bool basic_partition_map::is_logical(const std::string_view name) const { return false;
if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.isLogical; }
return false; basic_partition_map::_returnable_entry
} basic_partition_map::get_all(const std::string_view name) const {
if (const int pos = _index_of(name); name == _data[pos].name)
return _returnable_entry{_data[pos].props.size, _data[pos].props.isLogical};
basic_partition_map::_returnable_entry basic_partition_map::get_all(const std::string_view name) const { return _returnable_entry{};
if (const int pos = _index_of(name); name == _data[pos].name) }
return _returnable_entry{_data[pos].props.size, _data[pos].props.isLogical};
return _returnable_entry{}; bool basic_partition_map::find(const std::string_view name) const {
} if (name == _data[_index_of(name)].name) return true;
bool basic_partition_map::find(const std::string_view name) const { return false;
if (name == _data[_index_of(name)].name) return true; }
return false; std::string basic_partition_map::find_(const std::string &name) const {
} if (name == _data[_index_of(name)].name) return name;
std::string basic_partition_map::find_(const std::string &name) const { return {};
if (name == _data[_index_of(name)].name) return name; }
return {}; size_t basic_partition_map::size() const { return _count; }
}
size_t basic_partition_map::size() const { bool basic_partition_map::empty() const {
return _count; if (_count > 0) return false;
} return true;
}
bool basic_partition_map::empty() const { void basic_partition_map::clear() {
if (_count > 0) return false; LOGN(MAP, INFO) << "map clean requested. Map is empty now." << std::endl;
return true; delete[] _data;
} _count = 0;
_capacity = 6;
_data = new _entry[_capacity];
}
void basic_partition_map::clear() { basic_partition_map &
LOGN(MAP, INFO) << "map clean requested. Map is empty now." << std::endl; basic_partition_map::operator=(const basic_partition_map &map) {
delete[] _data; if (this != &map) {
_count = 0; delete[] _data;
_capacity = 6;
_data = new _entry[_capacity];
}
basic_partition_map &basic_partition_map::operator=(const basic_partition_map &map) { _capacity = map._capacity;
if (this != &map) { _count = map._count;
delete[] _data; _data = new _entry[_capacity];
std::copy(map._data, map._data + _count, _data);
}
_capacity = map._capacity; return *this;
_count = map._count; }
_data = new _entry[_capacity];
std::copy(map._data, map._data + _count, _data);
}
return *this; bool basic_partition_map::operator==(const basic_partition_map &other) const {
} if (this->_capacity != other._capacity || this->_count != other._count)
return false;
bool basic_partition_map::operator==(const basic_partition_map &other) const { for (size_t i = 0; i < _count; i++)
if (this->_capacity != other._capacity if (_data[i].name == other._data[i].name &&
|| this->_count != other._count) _data[i].props.size == other._data[i].props.size &&
return false; _data[i].props.isLogical == other._data[i].props.isLogical)
continue;
else return false;
for (size_t i = 0; i < _count; i++) return true;
if (_data[i].name == other._data[i].name }
&& _data[i].props.size == other._data[i].props.size
&& _data[i].props.isLogical == other._data[i].props.isLogical)
continue;
else
return false;
return true; bool basic_partition_map::operator!=(const basic_partition_map &other) const {
} return !(*this == other);
}
bool basic_partition_map::operator!=(const basic_partition_map &other) const { basic_partition_map::iterator basic_partition_map::begin() const {
return !(*this == other); return iterator(_data);
} }
basic_partition_map::iterator basic_partition_map::begin() const { basic_partition_map::iterator basic_partition_map::end() const {
return iterator(_data); return iterator(_data + _count);
} }
basic_partition_map::iterator basic_partition_map::end() const { basic_partition_map::constant_iterator basic_partition_map::cbegin() const {
return iterator(_data + _count); return constant_iterator(_data);
} }
basic_partition_map::constant_iterator basic_partition_map::cbegin() const { basic_partition_map::constant_iterator basic_partition_map::cend() const {
return constant_iterator(_data); return constant_iterator(_data + _count);
} }
basic_partition_map::constant_iterator basic_partition_map::cend() const {
return constant_iterator(_data + _count);
}
} // namespace PartitionMap } // namespace PartitionMap

100
srclib/libpartition_map/tests/test.cpp Executable file → Normal file
View File

@@ -15,66 +15,70 @@
*/ */
#include <iostream> #include <iostream>
#include <unistd.h>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
#include <unistd.h>
int main() { int main() {
if (getuid() != 0) return 2; if (getuid() != 0) return 2;
try { try {
PartitionMap::BuildMap MyMap; PartitionMap::BuildMap MyMap;
if (!MyMap) { if (!MyMap) {
MyMap.readDirectory("/dev/block/by-name"); MyMap.readDirectory("/dev/block/by-name");
if (!MyMap) throw PartitionMap::Error("Cannot generate object!"); if (!MyMap) throw PartitionMap::Error("Cannot generate object!");
} }
const auto map = MyMap.getAll(); const auto map = MyMap.getAll();
if (map.empty()) throw PartitionMap::Error("getAll() empty"); if (map.empty()) throw PartitionMap::Error("getAll() empty");
for (const auto& [name, props] : map) { for (const auto &[name, props] : map) {
std::cout << "Partition: " << name << ", size: " std::cout << "Partition: " << name << ", size: " << props.size
<< props.size << ", logical: " << ", logical: " << props.isLogical << std::endl;
<< props.isLogical << std::endl; }
}
const auto boot = MyMap.get("boot"); const auto boot = MyMap.get("boot");
if (!boot) throw PartitionMap::Error("get(\"boot\") returned nullopt"); if (!boot) throw PartitionMap::Error("get(\"boot\") returned nullopt");
std::cout << "Name: boot" << ", size: " std::cout << "Name: boot" << ", size: " << boot->first
<< boot->first << ", logical: " << ", logical: " << boot->second << std::endl;
<< boot->second << std::endl;
const auto logicals = MyMap.getLogicalPartitionList(); const auto logicals = MyMap.getLogicalPartitionList();
if (!logicals) throw PartitionMap::Error("getLogicalPartitionList() returned nullopt"); if (!logicals)
std::cout << "Logical partitions: " << std::endl; throw PartitionMap::Error("getLogicalPartitionList() returned nullopt");
for (const auto& name : *logicals) std::cout << "Logical partitions: " << std::endl;
std::cout << " - " << name << std::endl; for (const auto &name : *logicals)
std::cout << " - " << name << std::endl;
const auto physicals = MyMap.getPhysicalPartitionList(); const auto physicals = MyMap.getPhysicalPartitionList();
if (!physicals) throw PartitionMap::Error("getPhysicalPartitionList() returned nullopt"); if (!physicals)
std::cout << "Physical partitions: " << std::endl; throw PartitionMap::Error("getPhysicalPartitionList() returned nullopt");
for (const auto& name : *physicals) std::cout << "Physical partitions: " << std::endl;
std::cout << " - " << name << std::endl; for (const auto &name : *physicals)
std::cout << " - " << name << std::endl;
std::cout << "Boot: " << MyMap.getRealLinkPathOf("boot") << std::endl; std::cout << "Boot: " << MyMap.getRealLinkPathOf("boot") << std::endl;
std::cout << "Boot (realpath): " << MyMap.getRealPathOf("boot") << std::endl; std::cout << "Boot (realpath): " << MyMap.getRealPathOf("boot")
std::cout << "Search dir: " << MyMap.getCurrentWorkDir() << std::endl; << std::endl;
std::cout << "Has partition cache? = " << MyMap.hasPartition("cache") << std::endl; std::cout << "Search dir: " << MyMap.getCurrentWorkDir() << std::endl;
std::cout << "system partition is logical? = " << MyMap.isLogical("system") << std::endl; std::cout << "Has partition cache? = " << MyMap.hasPartition("cache")
std::cout << "Size of system partition: " << MyMap.sizeOf("system") << std::endl; << std::endl;
std::cout << "system partition is logical? = " << MyMap.isLogical("system")
<< std::endl;
std::cout << "Size of system partition: " << MyMap.sizeOf("system")
<< std::endl;
MyMap.clear(); MyMap.clear();
if (!MyMap.empty()) throw PartitionMap::Error("map cleaned but check fail"); if (!MyMap.empty()) throw PartitionMap::Error("map cleaned but check fail");
MyMap.readDirectory("/dev/block/by-name"); MyMap.readDirectory("/dev/block/by-name");
PartitionMap::BuildMap MyMap2; PartitionMap::BuildMap MyMap2;
if (MyMap == MyMap2) std::cout << "map1 = map2" << std::endl; if (MyMap == MyMap2) std::cout << "map1 = map2" << std::endl;
if (MyMap != MyMap2) std::cout << "map1 != map2" << std::endl; if (MyMap != MyMap2) std::cout << "map1 != map2" << std::endl;
std::cout << PartitionMap::getLibVersion() << std::endl; std::cout << PartitionMap::getLibVersion() << std::endl;
} catch (PartitionMap::Error& error) { } catch (PartitionMap::Error &error) {
std::cerr << error.what() << std::endl; std::cerr << error.what() << std::endl;
return 1; return 1;
} }
return 0; return 0;
} }