pmt: Improve performance and functions

- Added two new functions
 - Improved functions
 - Reformatted code (scripts and src/ include/)
 - Increased processing speed with multi-threading
This commit is contained in:
2025-08-07 14:49:24 +03:00
parent 6294482b39
commit 8b3e886eee
17 changed files with 678 additions and 453 deletions

View File

@@ -23,6 +23,9 @@ add_compile_options(-Wall -Werror -Wno-deprecated-declarations)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_options(-gdwarf-5 -fsanitize=address -fstack-protector)
add_link_options(-fsanitize=address)
else()
add_compile_options(-Os)
add_link_options(-s)
endif()
# Add pmt's CMake module(s)

View File

@@ -57,13 +57,15 @@ build()
cmake -B $BUILD_64 -S . $1 \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=$ANDROID_PLATFORM
-DANDROID_PLATFORM=$ANDROID_PLATFORM \
-DANDROID_STL=c++_static
echo "Configuring for armeabi-v7a..."
cmake -B $BUILD_32 -S . $1 \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=armeabi-v7a \
-DANDROID_PLATFORM=$ANDROID_PLATFORM
-DANDROID_PLATFORM=$ANDROID_PLATFORM \
-DANDROID_STL=c++_static
echo "Building arm64-v8a artifacts..."
cmake --build $BUILD_64

View File

@@ -34,73 +34,82 @@
#define PMTF "libpmt-function-manager"
namespace PartitionManager {
// All function classes must inherit from this class.
class basic_function {
public:
CLI::App *cmd = nullptr;
// All function classes must inherit from this class.
class basic_function {
public:
CLI::App* cmd = nullptr;
virtual bool init(CLI::App &_app) = 0;
virtual bool run() = 0;
virtual bool init(CLI::App& _app) = 0;
virtual bool run() = 0;
[[nodiscard]] virtual bool isUsed() const = 0;
[[nodiscard]] virtual const char* name() const = 0;
virtual ~basic_function() = default;
};
[[nodiscard]] virtual bool isUsed() const = 0;
[[nodiscard]] virtual const char *name() const = 0;
// A class for function management.
class basic_function_manager final {
private:
std::vector<std::unique_ptr<basic_function>> _functions;
virtual ~basic_function() = default;
};
public:
void registerFunction(std::unique_ptr<basic_function> _func, CLI::App& _app);
// A class for function management.
class basic_function_manager final {
private:
std::vector<std::unique_ptr<basic_function> > _functions;
[[nodiscard]] bool handleAll() const;
};
public:
void registerFunction(std::unique_ptr<basic_function> _func, CLI::App &_app);
// Sets logs file automatically
class logSetter final { public: logSetter(); };
[[nodiscard]] bool handleAll() const;
};
class basic_variables final {
private:
logSetter setLogSetting;
// Sets logs file automatically
class logSetter final { public: logSetter(); };
public:
basic_variables();
~basic_variables();
class basic_variables final {
private:
logSetter setLogSetting;
PartitionMap::BuildMap* PartMap;
public:
basic_variables();
~basic_variables();
std::string searchPath, logFile;
bool onLogical;
bool quietProcess;
bool verboseMode;
bool viewVersion;
bool forceProcess;
};
PartitionMap::BuildMap *PartMap;
using FunctionBase = basic_function;
using FunctionManager = basic_function_manager;
using VariableTable = basic_variables;
using Error = Helper::Error;
std::string searchPath, logFile;
bool onLogical;
bool quietProcess;
bool verboseMode;
bool viewVersion;
bool forceProcess;
};
extern VariableTable* Variables;
using FunctionBase = basic_function;
using FunctionManager = basic_function_manager;
using VariableTable = basic_variables;
using Error = Helper::Error;
int Main(int argc, char** argv);
extern VariableTable *Variables;
// Print messages if not using quiet mode
__attribute__((format(printf, 1, 2)))
void print(const char* format, ...);
int Main(int argc, char **argv);
// If there is a delimiter in the string, CLI::detail::split returns; if not, an empty vector is returned. And checks duplicate arguments.
std::vector<std::string> splitIfHasDelim(const std::string& s, char delim, bool checkForBadUsage = false);
// Print messages if not using quiet mode
__attribute__((format(printf, 1, 2)))
void print(const char *format, ...);
// Process vectors with input strings. Use for [flag(s)]-[other flag(s)] situations
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);
// Format it input and return
__attribute__((format(printf, 1, 2)))
std::string format(const char *format, ...);
std::string getLibVersion();
std::string getAppVersion(); // Not Android app version (an Android app is planned!), tells pmt version.
// If there is a delimiter in the string, CLI::detail::split returns; if not, an 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
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
void setupBufferSize(int &size, const std::string &partition);
std::string getLibVersion();
std::string getAppVersion(); // Not Android app version (an Android app is planned!), tells pmt version.
} // namespace PartitionManager
#endif // #ifndef LIBPMT_LIB_HPP

View File

@@ -23,6 +23,8 @@ set(PMT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/functions/FlashFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/InfoFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/PartitionSizeFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealPathFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealLinkPathFunction.cpp
)
# Add pmt
@@ -34,10 +36,3 @@ target_link_libraries(pmt PRIVATE helper_shared PRIVATE partition_map_shared)
target_link_libraries(pmt_static PRIVATE helper_static PRIVATE partition_map_static)
target_link_options(pmt PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
target_link_options(pmt_static PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
target_compile_options(pmt PRIVATE -Os)
target_compile_options(pmt_static PRIVATE -Os)
target_link_options(pmt PRIVATE -s)
target_link_options(pmt_static PRIVATE -s)
endif()

View File

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

View File

@@ -23,97 +23,110 @@
#include "functions/functions.hpp"
namespace PartitionManager {
auto Variables = new VariableTable();
auto Variables = new VariableTable();
logSetter::logSetter() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); }
logSetter::logSetter() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); }
basic_variables::~basic_variables() { delete PartMap; }
basic_variables::~basic_variables() { delete PartMap; }
basic_variables::basic_variables() : PartMap(new PartitionMap::BuildMap()),
logFile("/sdcard/Documents/last_pmt_logs.log"),
onLogical(false),
quietProcess(false),
verboseMode(false),
viewVersion(false),
forceProcess(false)
{}
basic_variables::basic_variables() : PartMap(new PartitionMap::BuildMap()),
logFile("/sdcard/Documents/last_pmt_logs.log"),
onLogical(false),
quietProcess(false),
verboseMode(false),
viewVersion(false),
forceProcess(false)
{}
int Main(int argc, char** argv)
{
try { // try-catch start
CLI::App AppMain{"Partition Manager Tool"};
FunctionManager FuncManager;
int Main(int argc, char **argv) {
try {
// try-catch start
CLI::App AppMain{"Partition Manager Tool"};
FunctionManager FuncManager;
AppMain.set_help_all_flag("--help-all", "Print full help message");
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.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check([&](const std::string& val) {
if (val.find("/block/") == std::string::npos) throw CLI::ValidationError("Partition search path is unexpected! Couldn't find 'block' in input path!");
return std::string();
});
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");
AppMain.fallthrough(true);
AppMain.set_help_all_flag("--help-all", "Print full help message");
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.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check(
[&](const std::string &val) {
if (val.find("/block") == std::string::npos) throw CLI::ValidationError(
"Partition search path is unexpected! Couldn't find 'block' in input path!");
return std::string();
});
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) {
print("Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.\n", argv[0]);
return EXIT_FAILURE;
if (argc < 2) {
print("Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.\n", argv[0]);
return EXIT_FAILURE;
}
FuncManager.registerFunction(std::make_unique<backupFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<flashFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<partitionSizeFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<realPathFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<realLinkPathFunction>(), AppMain);
CLI11_PARSE(AppMain, argc, argv);
if (Variables->verboseMode) Helper::LoggingProperties::setPrinting(YES);
if (Variables->viewVersion) {
print("%s\n", getAppVersion().data());
return EXIT_SUCCESS;
}
if (!Variables->searchPath.empty()) (*Variables->PartMap)(Variables->searchPath);
if (!Variables->PartMap && Variables->searchPath.empty())
throw Error("No default search entries were found. Specify a search directory with -S (--search-path)");
if (!Helper::hasSuperUser()) throw Error("This program requires super-user privileges!");
return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE;
} catch (Helper::Error &error) {
// catch Helper::Error
if (!Variables->quietProcess) fprintf(stderr, "%s%sERROR(S) OCCURRED%s:\n%s", RED, BOLD, STYLE_RESET,
error.what());
delete Variables;
return EXIT_FAILURE;
} catch (CLI::Error &error) {
// catch CLI::Error
delete Variables;
fprintf(stderr, "%s: %s%sFLAG PARSE ERROR:%s %s\n", argv[0], RED, BOLD, STYLE_RESET, error.what());
return EXIT_FAILURE;
} // try-catch block end
}
FuncManager.registerFunction(std::make_unique<backupFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<flashFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<partitionSizeFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain);
CLI11_PARSE(AppMain, argc, argv);
if (Variables->verboseMode) Helper::LoggingProperties::setPrinting(YES);
if (Variables->viewVersion) {
print("%s\n", getAppVersion().data());
return EXIT_SUCCESS;
void print(const char *format, ...) {
va_list args;
va_start(args, format);
if (!Variables->quietProcess) vfprintf(stdout, format, args);
va_end(args);
}
if (!Variables->searchPath.empty()) (*Variables->PartMap)(Variables->searchPath);
std::string format(const char *format, ...) {
va_list args;
va_start(args, format);
char str[1024];
vsnprintf(str, sizeof(str), format, args);
va_end(args);
return str;
}
if (!Variables->PartMap && Variables->searchPath.empty())
throw Error("No default search entries were found. Specify a search directory with -S (--search-path)");
return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE;
} catch (Helper::Error &error) { // catch Helper::Error
if (!Variables->quietProcess) fprintf(stderr, "%s: %s.\n", argv[0], error.what());
delete Variables;
return EXIT_FAILURE;
} catch (CLI::Error &error) { // catch CLI::Error
delete Variables;
fprintf(stderr, "%s: FLAG PARSE ERROR: %s\n", argv[0], error.what());
return EXIT_FAILURE;
} // try-catch block end
}
void print(const char* format, ...)
{
va_list args;
va_start(args, format);
if (!Variables->quietProcess) vfprintf(stdout, format, args);
va_end(args);
}
std::string getLibVersion()
{
MKVERSION(PMT);
}
std::string getAppVersion()
{
MKVERSION(PMTE);
}
std::string getLibVersion() {
MKVERSION(PMT);
}
std::string getAppVersion() {
MKVERSION(PMTE);
}
} // namespace PartitionManager

View File

@@ -1,5 +1,5 @@
/*
Copyright 2025 Yağız Zengin
Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,62 +18,47 @@ Copyright 2025 Yağız Zengin
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <future>
#include <chrono>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define BFUN "backupFunction"
namespace PartitionManager {
pair backupFunction::runAsync(const std::string &partitionName, const std::string &outputName, int bufferSize) {
if (!Variables->PartMap->hasPartition(partitionName)) return {
format("Couldn't find partition: %s", partitionName.data()), false
};
bool backupFunction::init(CLI::App &_app)
{
LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl;
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required();
cmd->add_option("output(s)", rawOutputNames, "File name(s) (or path(s)) to save the partition image(s)");
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading partition(s) and writing to file(s)");
return true;
}
bool backupFunction::run()
{
processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames, ',', true);
if (!outputNames.empty() && partitions.size() != outputNames.size())
throw CLI::ValidationError("You must provide an output name(s) as long as the partition name(s)");
for (size_t i = 0; i < partitions.size(); i++) {
std::string partitionName = partitions[i];
std::string outputName = outputNames.empty() ? partitionName + ".img" : outputNames[i];
LOGN(BFUN, INFO) << "backupping " << partitionName << " as " << outputName << std::endl;
if (!Variables->PartMap->hasPartition(partitionName))
throw Error("Couldn't find partition: %s", partitionName.data());
LOGN(BFUN, INFO) << "back upping " << partitionName << " as " << outputName << std::endl;
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) LOGN(BFUN, WARNING) << "Partition " << partitionName << " is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data());
if (Variables->forceProcess)
LOGN(BFUN, WARNING) << "Partition " << partitionName <<
" 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) throw Error("%s is exists. Remove it, or use --force (-f) flag.", outputName.data());
else LOGN(BFUN, INFO) << outputName << " is exists but ignoring (from --force, -f). Re-creating." << std::endl;
if (Helper::fileIsExists(outputName) && !Variables->forceProcess) return {
format("%s is exists. Remove it, or use --force (-f) flag.", outputName.data()), false
};
bufferSize = (Variables->PartMap->sizeOf(partitionName) % bufferSize == 0) ? bufferSize : 1;
LOGN(BFUN, INFO) << "Using buffer size: " << bufferSize << std::endl;
setupBufferSize(bufferSize, partitionName);
LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName << "): " << bufferSize << std::endl;
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDONLY);
if (pfd < 0)
throw Error("Can't open partition: %s: %s", partitionName.data(), strerror(errno));
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
const int ffd = open(outputName.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ffd < 0) {
close(pfd);
throw Error("Can't create/open output file %s: %s", outputName.data(), strerror(errno));
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;
auto* buffer = new char[bufferSize];
auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize);
ssize_t bytesRead;
while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) {
@@ -81,21 +66,61 @@ bool backupFunction::run()
close(pfd);
close(ffd);
delete[] buffer;
throw Error("Can't write partition to output file %s: %s", outputName.data(), strerror(errno));
return {
format("Can't write partition to output file %s: %s", outputName.data(), strerror(errno)), false
};
}
}
close(pfd);
close(ffd);
delete[] buffer;
return {format("%s partition successfully back upped to %s", partitionName.data(), outputName.data()), true};
}
LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl;
return true;
}
bool backupFunction::init(CLI::App &_app) {
LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl;
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required();
cmd->add_option("output(s)", rawOutputNames, "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)");
bool backupFunction::isUsed() const { return cmd->parsed(); }
return true;
}
const char* backupFunction::name() const { return BFUN; }
bool backupFunction::run() {
processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames, ',', true);
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;
for (size_t i = 0; i < partitions.size(); i++) {
std::string partitionName = partitions[i];
std::string outputName = 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));
LOGN(BFUN, INFO) << "Created thread backup upping " << partitionName << std::endl;
}
std::string end;
bool endResult = true;
for (auto &future: futures) {
auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; }
else print("%s\n", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());
LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult;
}
bool backupFunction::isUsed() const { return cmd->parsed(); }
const char *backupFunction::name() const { return BFUN; }
} // namespace PartitionManager

View File

@@ -17,6 +17,7 @@ Copyright 2025 Yağız Zengin
#include <cstdlib>
#include <fcntl.h>
#include <cerrno>
#include <future>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
@@ -24,38 +25,31 @@ Copyright 2025 Yağız Zengin
#define EFUN "eraseFunction"
namespace PartitionManager {
bool eraseFunction::init(CLI::App &_app)
{
LOGN(EFUN, INFO) << "Initializing variables of erase function." << std::endl;
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("-b,--buffer-size", bufferSize, "Buffer size for writing zero bytes to partition(s)");
return true;
}
bool eraseFunction::run()
{
for (const auto& partitionName : partitions) {
if (!Variables->PartMap->hasPartition(partitionName))
throw Error("Couldn't find partition: %s", partitionName.data());
pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
if (!Variables->PartMap->hasPartition(partitionName)) return {
format("Couldn't find partition: %s", partitionName.data()), false
};
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) LOGN(EFUN, WARNING) << "Partition " << partitionName << " is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data());
if (Variables->forceProcess)
LOGN(EFUN, WARNING) << "Partition " << partitionName <<
" 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
};
}
bufferSize = (Variables->PartMap->sizeOf(partitionName) % bufferSize == 0) ? bufferSize : 1;
setupBufferSize(bufferSize, partitionName);
LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize;
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_WRONLY);
if (pfd < 0)
throw Error("Can't open partition: %s: %s", partitionName.data(), strerror(errno));
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
if (!Variables->forceProcess) 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!");
if (!Variables->forceProcess) 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;
auto* buffer = new char[bufferSize];
auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize);
ssize_t bytesWritten = 0;
const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName);
@@ -67,20 +61,48 @@ bool eraseFunction::run()
if (const ssize_t result = write(pfd, buffer, toWrite); result == -1) {
close(pfd);
delete[] buffer;
throw Error("Can't write zero bytes to partition: %s: %s", partitionName.data(), strerror(errno));
return {
format("Can't write zero bytes to partition: %s: %s", partitionName.data(), strerror(errno)), false
};
} else bytesWritten += result;
}
close(pfd);
delete[] buffer;
return {format("Successfully wrote zero bytes to the %s partition\n", partitionName.data()), true};
}
LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl;
return true;
}
bool eraseFunction::init(CLI::App &_app) {
LOGN(EFUN, INFO) << "Initializing variables of erase function." << std::endl;
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("-b,--buffer-size", bufferSize, "Buffer size for writing zero bytes to partition(s)");
return true;
}
bool eraseFunction::isUsed() const { return cmd->parsed(); }
bool eraseFunction::run() {
std::vector<std::future<pair> > futures;
for (const auto &partitionName: partitions) {
futures.push_back(std::async(std::launch::async, runAsync, partitionName, bufferSize));
LOGN(EFUN, INFO) << "Created thread for writing zero bytes to " << partitionName << std::endl;
}
const char* eraseFunction::name() const { return EFUN; }
std::string end;
bool endResult = true;
for (auto &future: futures) {
auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; }
else print("%s\n", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());
LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult;
}
bool eraseFunction::isUsed() const { return cmd->parsed(); }
const char *eraseFunction::name() const { return EFUN; }
} // namespace PartitionManager

View File

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

View File

@@ -24,66 +24,67 @@ Copyright 2025 Yağız Zengin
#define IFUN "infoFunction"
namespace PartitionManager {
bool infoFunction::init(CLI::App &_app)
{
LOGN(IFUN, INFO) << "Initializing variables of info printer function." << std::endl;
cmd = _app.add_subcommand("info", "Tell info(s) of input partition list")->footer("Use get-all as partition name for getting info's of all partitions.");
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(',');
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()
{
if (partitions.back() == "get-all") {
partitions.clear();
const auto parts = Variables->PartMap->getPartitionList();
if (!parts) 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);
bool infoFunction::init(CLI::App &_app) {
LOGN(IFUN, INFO) << "Initializing variables of info printer function." << std::endl;
cmd = _app.add_subcommand("info", "Tell info(s) of input partition list")->footer(
"Use get-all or getvar-all as partition name for getting info's of all partitions.");
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(',');
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;
}
for (const auto& partition : partitions) {
if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data());
bool infoFunction::run() {
if (partitions.back() == "get-all" || partitions.back() == "getvar-all") {
partitions.clear();
const auto parts = Variables->PartMap->getPartitionList();
if (!parts) throw Error("Cannot get list of all partitions! See logs for more information (%s)",
Helper::LoggingProperties::FILE.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess) LOGN(IFUN, 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());
}
for (const auto &name: *parts) partitions.push_back(name);
}
if (jsonFormat)
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(IFUN, 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());
}
if (jsonFormat)
#ifdef __LP64__
print("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}\n",
print("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}\n",
#else
print("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}\n",
print("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}\n",
#endif
jNamePartition.data(),
partition.data(),
jNameSize.data(),
Variables->PartMap->sizeOf(partition),
jNameLogical.data(),
Variables->PartMap->isLogical(partition) ? "true" : "false");
else
jNamePartition.data(),
partition.data(),
jNameSize.data(),
Variables->PartMap->sizeOf(partition),
jNameLogical.data(),
Variables->PartMap->isLogical(partition) ? "true" : "false");
else
#ifdef __LP64__
print("partition=%s size=%lu isLogical=%s\n",
print("partition=%s size=%lu isLogical=%s\n",
#else
print("partition=%s size=%llu isLogical=%s\n",
print("partition=%s size=%llu isLogical=%s\n",
#endif
partition.data(),
Variables->PartMap->sizeOf(partition),
Variables->PartMap->isLogical(partition) ? "true" : "false");
}
partition.data(),
Variables->PartMap->sizeOf(partition),
Variables->PartMap->isLogical(partition) ? "true" : "false");
}
return true;
}
return true;
}
bool infoFunction::isUsed() const { return cmd->parsed(); }
const char* infoFunction::name() const { return IFUN; };
bool infoFunction::isUsed() const { return cmd->parsed(); }
const char *infoFunction::name() const { return IFUN; };
} // namespace PartitionManager

View File

@@ -19,8 +19,7 @@ Copyright 2025 Yağız Zengin
#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 == "MB") return std::to_string(TO_MB(size));
if (multiple == "GB") return std::to_string(TO_GB(size));
@@ -28,45 +27,44 @@ std::string convertTo(const uint64_t size, const std::string& multiple)
}
namespace PartitionManager {
bool partitionSizeFunction::init(CLI::App& _app)
{
LOGN(SFUN, INFO) << "Initializing variables of partition size getter function." << std::endl;
cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list");
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(',');
cmd->add_flag("--as-byte", asByte, "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.");
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());
}
std::string multiple;
if (asByte) multiple = "B";
if (asKiloBytes) multiple = "KB";
if (asMega) multiple = "MB";
if (asGiga) multiple = "GB";
print("%s: %s%s\n", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(), multiple.data());
bool partitionSizeFunction::init(CLI::App &_app) {
LOGN(SFUN, INFO) << "Initializing variables of partition size getter function." << std::endl;
cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list");
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(',');
cmd->add_flag("--as-byte", asByte, "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.");
return true;
}
return true;
}
bool partitionSizeFunction::run() {
for (const auto &partition: partitions) {
if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data());
bool partitionSizeFunction::isUsed() const { return cmd->parsed(); }
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());
}
const char* partitionSizeFunction::name() const { return SFUN; }
std::string multiple = "MB";
if (asByte) multiple = "B";
if (asKiloBytes) multiple = "KB";
if (asMega) multiple = "MB";
if (asGiga) multiple = "GB";
print("%s: %s%s\n", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(),
multiple.data());
}
return true;
}
bool partitionSizeFunction::isUsed() const { return cmd->parsed(); }
const char *partitionSizeFunction::name() const { return SFUN; }
} // namespace PartitionManager

View File

@@ -0,0 +1,51 @@
/*
Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define RLPFUN "realPathFunction"
namespace PartitionManager {
bool realLinkPathFunction::init(CLI::App &_app) {
LOGN(RLPFUN, INFO) << "Initializing variables of real link path function." << std::endl;
cmd = _app.add_subcommand("real-linkpath", "Tell real link paths of partition(s)");
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required();
return true;
}
bool realLinkPathFunction::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(RLPFUN, 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());
}
print("%s\n", Variables->PartMap->getRealPathOf(partition).data());
}
return true;
}
bool realLinkPathFunction::isUsed() const { return cmd->parsed(); }
const char *realLinkPathFunction::name() const { return RLPFUN; }
} // namespace PartitionManager

View File

@@ -0,0 +1,51 @@
/*
Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define RPFUN "realPathFunction"
namespace PartitionManager {
bool realPathFunction::init(CLI::App &_app) {
LOGN(RPFUN, INFO) << "Initializing variables of real path function." << std::endl;
cmd = _app.add_subcommand("real-path", "Tell real paths of partition(s)");
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required();
return true;
}
bool realPathFunction::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(RPFUN, 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());
}
print("%s\n", Variables->PartMap->getRealPathOf(partition).data());
}
return true;
}
bool realPathFunction::isUsed() const { return cmd->parsed(); }
const char *realPathFunction::name() const { return RPFUN; }
} // namespace PartitionManager

View File

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

View File

@@ -42,7 +42,7 @@ struct _entry {
* The main type of the library. The Builder class is designed
* to be easily manipulated and modified only on this class.
*/
class basic_partition_map {
class basic_partition_map final {
private:
void _resize_map();
[[nodiscard]] int _index_of(std::string_view name) const;
@@ -116,7 +116,7 @@ public:
using Map_t = basic_partition_map;
class basic_partition_map_builder {
class basic_partition_map_builder final {
private:
Map_t _current_map;
std::string _workdir;

View File

@@ -81,7 +81,7 @@ std::string basic_partition_map_builder::getRealPathOf(const std::string_view na
{
_map_build_check();
std::string full = _workdir + "/" + name.data();
const std::string full = (isLogical(name)) ? std::string("/dev/block/mapper/") + name.data() : _workdir + "/" + name.data();
if (!_current_map.find(name)
|| !std::filesystem::is_symlink(full))
return {};

View File

@@ -156,24 +156,21 @@ void basic_partition_map::merge(const basic_partition_map& map)
uint64_t basic_partition_map::get_size(const std::string_view name) const
{
int pos = _index_of(name);
if (name == _data[pos].name) return _data[pos].props.size;
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
{
int pos = _index_of(name);
if (name == _data[pos].name) return _data[pos].props.isLogical;
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
{
int pos = _index_of(name);
if (name == _data[pos].name)
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{};