pmt: ready for release

- Fix memory leaks
 - Writed functions and apply
 - Test pmt and verify stability
This commit is contained in:
2025-08-06 21:58:05 +03:00
parent 670f2bfad5
commit 6294482b39
29 changed files with 1033 additions and 502 deletions

14
.gitignore vendored
View File

@@ -1,2 +1,16 @@
# Dont'd add IDE files
cmake-build-* cmake-build-*
.idea .idea
.vscode
# Don't add generated headers
include/generated
# Dont't add build directories
build_arm64-v8a
build_armeabi-v7a
# Don't add generated objects and libs
*.o
*.so
*.a

2
.idea/editor.xml generated
View File

@@ -269,7 +269,7 @@
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" /> <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" /> <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" /> <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" /> <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Tab" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" /> <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" /> <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />

View File

@@ -19,7 +19,7 @@ cmake_minimum_required(VERSION 3.10)
project(pmt VERSION 1.0.0) project(pmt VERSION 1.0.0)
# Set compiler flags # Set compiler flags
add_compile_options(-Wall -Werror) add_compile_options(-Wall -Werror -Wno-deprecated-declarations)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_options(-gdwarf-5 -fsanitize=address -fstack-protector) add_compile_options(-gdwarf-5 -fsanitize=address -fstack-protector)
add_link_options(-fsanitize=address) add_link_options(-fsanitize=address)
@@ -38,4 +38,5 @@ include_directories(include srclib/libhelper/include srclib/libpartition_map/inc
# Add libraries # Add libraries
add_subdirectory(srclib) add_subdirectory(srclib)
# NOTE: pmt is not ready, this CMakeFiles.txt only builds libraries # Include pmt
add_subdirectory(src)

View File

@@ -14,27 +14,18 @@
limitations under the License. limitations under the License.
*/ */
/**
* WARNING
* --------
* This library (libpmt) isn't exactly suitable for use in different projects.
* But I'm not saying I've tested it or anything like that.
*/
#ifndef LIBPMT_LIB_HPP #ifndef LIBPMT_LIB_HPP
#define LIBPMT_LIB_HPP #define LIBPMT_LIB_HPP
#include <list>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <functional>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignore "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include <CLI/CLI11.hpp> #include <CLI/CLI11.hpp>
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@@ -44,48 +35,48 @@
namespace PartitionManager { namespace PartitionManager {
/** // All function classes must inherit from this class.
* basic_function
* --------------
* 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;
virtual const char* name() = 0; [[nodiscard]] virtual bool isUsed() const = 0;
[[nodiscard]] virtual const char* name() const = 0;
virtual ~basic_function() = default; virtual ~basic_function() = default;
}; };
/** // A class for function management.
* basic_function_manager class basic_function_manager final {
* ----------------------
* A class for function management.
*/
class basic_function_manager {
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);
const char* whatIsRunnedCommandName();
bool handleAll(); [[nodiscard]] bool handleAll() const;
}; };
class basic_variables { // Sets logs file automatically
class logSetter final { public: logSetter(); };
class basic_variables final {
private:
logSetter setLogSetting;
public: public:
basic_variables(); basic_variables();
~basic_variables();
PartitionMap::BuildMap PartMap; PartitionMap::BuildMap* PartMap;
std::string searchPath; std::string searchPath, logFile;
bool onLogical; bool onLogical;
bool silentProcess; bool quietProcess;
bool verboseMode; bool verboseMode;
bool viewVersion; bool viewVersion;
bool forceProcess;
}; };
using FunctionBase = basic_function; using FunctionBase = basic_function;
@@ -93,10 +84,20 @@ using FunctionManager = basic_function_manager;
using VariableTable = basic_variables; using VariableTable = basic_variables;
using Error = Helper::Error; using Error = Helper::Error;
VariableTable* Variables; extern VariableTable* Variables;
int Main(int argc, char** argv); int Main(int argc, char** argv);
// Print messages if not using quiet mode
__attribute__((format(printf, 1, 2)))
void print(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.
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);
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.

43
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,43 @@
#
# 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.
#
set(PMT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/FunctionManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/PartitionManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/BackupFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/EraseFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/FlashFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/InfoFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/PartitionSizeFunction.cpp
)
# Add pmt
add_executable(pmt ${PMT_SOURCES})
add_executable(pmt_static ${PMT_SOURCES})
# Set linker options
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

@@ -17,37 +17,56 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <string> #include <string>
#include <PartitionManager/lib.hpp> #include <unordered_set>
#include <PartitionManager/PartitionManager.hpp>
namespace PartitionManager { 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);
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 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) void basic_function_manager::registerFunction(std::unique_ptr<basic_function> _func, CLI::App& _app)
{ {
LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl; LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl;
if (!_func->init(_app)) throw Error("Cannot init function: %s\n", _func->name()); if (!_func->init(_app)) throw Error("Cannot init function: %s\n", _func->name());
_functions.push_back(std::move(_func)); _functions.push_back(std::move(_func));
LOGN(PMTF, INFO) << _func->name() << " successfully registered." << std::endl; LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered." << std::endl;
} }
const char* basic_function_manager::whatIsRunnedCommandName() bool basic_function_manager::handleAll() const
{ {
for (auto &func : _functions) { LOGN(PMTF, INFO) << "running caught function commands in command-line." << std::endl;
if (func->cmd->parsed()) return func->name(); for (const auto& func : _functions) {
} if (func->isUsed()) {
LOGN(PMTF, INFO) << func->name() << " is calling because used in command-line." << std::endl;
return nullptr; return func->run();
}
bool basic_function_manager::handleAll()
{
LOGN(PMTF, INFO) << "running catched function commands in command-line." << std::endl;
for (auto &func : _functions) {
if (func->cmd->parsed()) {
LOGN(PMTF, INFO) << "running function: " << func->name() << std::endl;
return (func->run()) ? true : false;
} }
} }
LOGN(PMTF, INFO) << "not found any used function from command-line." << std::endl;
print("Target progress is not specified. Specify a progress.");
return false; return false;
} }

View File

@@ -1,97 +0,0 @@
/*
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 <string>
#include <stdio.h>
#include <stdlib.h>
#include <PartitionManager/lib.hpp>
#include <generated/buildInfo.hpp>
#include "functions/functions.hpp"
namespace PartitionManager {
basic_variables::basic_variables() : PartMap(),
searchPath(""),
onLogical(false),
silentProcess(false),
verboseMode(false),
viewVersion(false)
{}
VariableTable* Variables = new VariableTable();
int Main(int argc, char** argv)
{
try { // try-catch start
CLI::App AppMain{"Partition Manager Tool"};
FunctionManager FuncManager;
AppMain.add_option("-S,--search-path", Variables->searchPath, "Set partition search path");
AppMain.add_flag("-l,--logical", Variables->onLogical, "Specify that the target partition is dynamic");
AppMain.add_flag("-s,--silent", Variables->silentProcess, "The process is performed silently without any output.");
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");
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);
CLI11_PARSE(AppMain, argc, argv);
const char* used = FuncManager.whatIsRunnedCommandName();
if (used != nullptr)
LOGN(PMTE, INFO) << "used command: " << used << std::endl;
if (!Variables->searchPath.empty())
Variables->PartMap(Variables->searchPath);
if (!Variables->PartMap) {
if (Variables->searchPath.empty())
throw Error("No default search entries were found. Specify a search directory with -S (--search-path)");
}
FuncManager.handleAll();
} catch (Helper::Error &error) { // catch Helper::Error
if (!Variables->silentProcess) fprintf(stderr, "%s: %s.\n", argv[0], error.what());
delete Variables;
return -1;
} catch (CLI::ParseError &error) { // catch CLI::ParseError
fprintf(stderr, "%s: FLAG PARSE ERROR: %s\n", argv[0], error.what());
return -1;
} // try-catch block end
}
std::string getLibVersion()
{
char vinfo[512];
sprintf(vinfo, MKVERSION("libpmt"));
return std::string(vinfo);
}
std::string getAppVersion()
{
char vinfo[512];
sprintf(vinfo, MKVERSION("pmt"));
return std::string(vinfo);
}
} // namespace PartitionManager

View File

@@ -14,10 +14,11 @@
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/lib.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);
return PartitionManager::Main(argc, argv); return PartitionManager::Main(argc, argv);
} }

119
src/PartitionManager.cpp Executable file
View File

@@ -0,0 +1,119 @@
/*
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 <string>
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <PartitionManager/PartitionManager.hpp>
#include <generated/buildInfo.hpp>
#include "functions/functions.hpp"
namespace PartitionManager {
auto Variables = new VariableTable();
logSetter::logSetter() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); }
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)
{}
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");
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);
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)");
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);
}
} // namespace PartitionManager

View File

@@ -0,0 +1,101 @@
/*
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 <cstdlib>
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define BFUN "backupFunction"
namespace PartitionManager {
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());
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 (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;
bufferSize = (Variables->PartMap->sizeOf(partitionName) % bufferSize == 0) ? bufferSize : 1;
LOGN(BFUN, INFO) << "Using buffer size: " << 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));
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));
}
LOGN(BFUN, INFO) << "Writing partition " << partitionName << " to file: " << outputName << std::endl;
auto* buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize);
ssize_t bytesRead;
while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) {
if (const ssize_t bytesWritten = write(ffd, buffer, bytesRead); bytesWritten != bytesRead) {
close(pfd);
close(ffd);
delete[] buffer;
throw Error("Can't write partition to output file %s: %s", outputName.data(), strerror(errno));
}
}
close(pfd);
close(ffd);
delete[] buffer;
}
LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl;
return true;
}
bool backupFunction::isUsed() const { return cmd->parsed(); }
const char* backupFunction::name() const { return BFUN; }
} // namespace PartitionManager

View File

@@ -0,0 +1,86 @@
/*
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 <cstdlib>
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#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());
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());
}
bufferSize = (Variables->PartMap->sizeOf(partitionName) % bufferSize == 0) ? bufferSize : 1;
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 (!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];
memset(buffer, 0x00, bufferSize);
ssize_t bytesWritten = 0;
const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName);
while (bytesWritten < partitionSize) {
size_t toWrite = sizeof(buffer);
if (partitionSize - bytesWritten < sizeof(buffer)) toWrite = partitionSize - bytesWritten;
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));
} else bytesWritten += result;
}
close(pfd);
delete[] buffer;
}
LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl;
return true;
}
bool eraseFunction::isUsed() const { return cmd->parsed(); }
const char* eraseFunction::name() const { return EFUN; }
} // namespace PartitionManager

View File

@@ -0,0 +1,104 @@
/*
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 <cstdlib>
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#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];
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());
}
bufferSize = (Helper::fileSize(imageName) % bufferSize == 0) ? bufferSize : 1;
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));
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));
}
LOGN(FFUN, INFO) << "Writing image " << imageName << " to partition: " << partitionName << std::endl;
auto* buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize);
ssize_t bytesRead;
while ((bytesRead = read(ffd, buffer, bufferSize)) > 0) {
if (const ssize_t bytesWritten = write(pfd, buffer, bytesRead); bytesWritten != bytesRead) {
close(pfd);
close(ffd);
delete[] buffer;
throw Error("Can't write partition to output file %s: %s", imageName.data(), strerror(errno));
}
}
close(pfd);
close(ffd);
delete[] buffer;
}
LOGN(FFUN, INFO) << "Operation successfully completed." << std::endl;
return true;
}
bool flashFunction::isUsed() const { return cmd->parsed(); }
const char* flashFunction::name() const { return FFUN; }
} // namespace PartitionManager

View File

@@ -0,0 +1,89 @@
/*
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 <cstdlib>
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#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);
}
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",
#else
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
#ifdef __LP64__
print("partition=%s size=%lu isLogical=%s\n",
#else
print("partition=%s size=%llu isLogical=%s\n",
#endif
partition.data(),
Variables->PartMap->sizeOf(partition),
Variables->PartMap->isLogical(partition) ? "true" : "false");
}
return true;
}
bool infoFunction::isUsed() const { return cmd->parsed(); }
const char* infoFunction::name() const { return IFUN; };
} // namespace PartitionManager

View File

@@ -0,0 +1,72 @@
/*
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 SFUN "partitionSizeFunction"
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));
return std::to_string(size);
}
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());
}
return true;
}
bool partitionSizeFunction::isUsed() const { return cmd->parsed(); }
const char* partitionSizeFunction::name() const { return SFUN; }
} // namespace PartitionManager

View File

@@ -14,48 +14,92 @@
limitations under the License. limitations under the License.
*/ */
#include <PartitionManager/lib.hpp> #ifndef FUNCTIONS_HPP
#define FUNCTIONS_HPP
#include <PartitionManager/PartitionManager.hpp>
#include <vector>
namespace PartitionManager { namespace PartitionManager {
// Back-up function // Back-up function
class backupFunction : public PartitionManager::FunctionBase { class backupFunction final : public FunctionBase {
private:
std::vector<std::string> partitions, outputNames;
std::string rawPartitions, rawOutputNames;
int bufferSize = 2048;
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;
const char* name() override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char* name() const override;
}; };
// Image flasher function // Image flasher function
class flashFunction : public PartitionManager::FunctionBase { class flashFunction final : public FunctionBase {
private:
std::vector<std::string> partitions, imageNames;
std::string rawPartitions, rawImageNames;
int bufferSize = 2048;
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;
const char* name() override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char* name() const override;
}; };
// Eraser function (only the partition content is cleared) // Eraser function (writes zero bytes to partition)
class eraseFunction : public PartitionManager::FunctionBase { class eraseFunction final : public FunctionBase {
private:
std::vector<std::string> partitions;
int bufferSize = 2048;
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;
const char* name() override; [[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char* name() const override;
}; };
// Partition size getter function // Partition size getter function
class partitionSizeFunction : public PartitionManager::FunctionBase { class partitionSizeFunction final : public FunctionBase {
private:
std::vector<std::string> partitions;
bool onlySize = false, asByte = false, asKiloBytes = false, asMega = true, 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;
const char* name() 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;
}; };
} // namespace PartitionManager } // namespace PartitionManager
#endif // #ifndef FUNCTIONS_HPP

View File

@@ -25,13 +25,17 @@ set(LIBHELPER_SOURCES
# Add targets # Add targets
add_library(helper_shared SHARED ${LIBHELPER_SOURCES}) add_library(helper_shared SHARED ${LIBHELPER_SOURCES})
add_library(helper_static STATIC ${LIBHELPER_SOURCES}) add_library(helper_static STATIC ${LIBHELPER_SOURCES})
add_executable(libhelper_test tests/test.cpp)
# Set linker flags # Set linker flags
target_link_libraries(libhelper_test PRIVATE helper_shared)
target_link_options(libhelper_test PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib" "LINKER:-rpath,/data/local")
target_link_options(helper_shared PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") target_link_options(helper_shared PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
# Set appropriate output names # Set appropriate output names
set_target_properties(helper_shared PROPERTIES OUTPUT_NAME "helper") set_target_properties(helper_shared PROPERTIES OUTPUT_NAME "helper")
set_target_properties(helper_static PROPERTIES OUTPUT_NAME "helper") set_target_properties(helper_static PROPERTIES OUTPUT_NAME "helper")
# Build libhelper_test if CMAKE_BUILD_TYPE is not release
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
add_executable(libhelper_test ${CMAKE_CURRENT_SOURCE_DIR}/tests/test.cpp)
target_link_libraries(libhelper_test PRIVATE helper_shared)
target_link_options(libhelper_test PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
endif()

View File

@@ -26,10 +26,10 @@
#ifndef ONLY_HELPER_MACROS #ifndef ONLY_HELPER_MACROS
enum LogLevels { enum LogLevels {
INFO = (int)'I', INFO = static_cast<int>('I'),
WARNING = (int)'W', WARNING = static_cast<int>('W'),
ERROR = (int)'E', ERROR = static_cast<int>('E'),
ABORT = (int)'A' ABORT = static_cast<int>('A')
}; };
constexpr mode_t DEFAULT_FILE_PERMS = 0644; constexpr mode_t DEFAULT_FILE_PERMS = 0644;
@@ -41,7 +41,7 @@ constexpr int NO = 0;
namespace Helper { namespace Helper {
// Logging // Logging
class Logger { class Logger final {
private: private:
LogLevels _level; LogLevels _level;
std::ostringstream _oss; std::ostringstream _oss;
@@ -62,14 +62,15 @@ public:
}; };
// Throwable error class // Throwable error class
class Error : public std::exception { class Error final : public std::exception {
private: private:
std::string _message; std::string _message;
public: public:
Error(const char* format, ...); __attribute__((format(printf, 2, 3)))
explicit Error(const char* format, ...);
const char* what() const noexcept override; [[nodiscard]] const char* what() const noexcept override;
}; };
namespace LoggingProperties { namespace LoggingProperties {
@@ -88,48 +89,50 @@ void reset();
// Checkers // Checkers
bool hasSuperUser(); bool hasSuperUser();
bool isExists(const std::string_view entry); bool isExists(std::string_view entry);
bool fileIsExists(const std::string_view file); bool fileIsExists(std::string_view file);
bool directoryIsExists(const std::string_view directory); bool directoryIsExists(std::string_view directory);
bool linkIsExists(const std::string_view entry); bool linkIsExists(std::string_view entry);
bool isLink(const std::string_view entry); bool isLink(std::string_view entry);
bool isSymbolicLink(const std::string_view entry); bool isSymbolicLink(std::string_view entry);
bool isHardLink(const std::string_view entry); bool isHardLink(std::string_view entry);
bool areLinked(const std::string_view entry1, const std::string_view entry2); bool areLinked(std::string_view entry1, std::string_view entry2);
// File I/O // File I/O
bool writeFile(const std::string_view file, const std::string_view text); bool writeFile(std::string_view file, std::string_view text);
std::optional<std::string> readFile(const std::string_view file); std::optional<std::string> readFile(std::string_view file);
// Creators // Creators
bool makeDirectory(const std::string_view path); bool makeDirectory(std::string_view path);
bool makeRecursiveDirectory(const std::string_view paths); bool makeRecursiveDirectory(std::string_view paths);
bool createFile(const std::string_view path); bool createFile(std::string_view path);
bool createSymlink(const std::string_view entry1, const std::string_view entry2); bool createSymlink(std::string_view entry1, std::string_view entry2);
// Removers // Removers
bool eraseEntry(const std::string_view entry); bool eraseEntry(std::string_view entry);
bool eraseDirectoryRecursive(const std::string_view directory); bool eraseDirectoryRecursive(std::string_view directory);
// Getters // Getters
size_t fileSize(const std::string_view file); size_t fileSize(std::string_view file);
std::string readSymlink(const std::string_view entry); std::string readSymlink(std::string_view entry);
// SHA-256 // SHA-256
bool sha256Compare(const std::string_view file1, const std::string_view file2); bool sha256Compare(std::string_view file1, std::string_view file2);
std::optional<std::string> sha256Of(const std::string_view path); std::optional<std::string> sha256Of(std::string_view path);
// Utilities // Utilities
bool copyFile(const std::string_view file, const std::string_view dest); bool copyFile(std::string_view file, std::string_view dest);
bool runCommand(const std::string_view cmd); bool runCommand(std::string_view cmd);
bool confirmPropt(const std::string_view message); bool confirmPropt(std::string_view message);
bool changeMode(std::string_view file, mode_t mode);
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(const 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(const std::string_view entry); std::string pathBasename(std::string_view entry);
std::string pathDirname(const std::string_view entry); std::string pathDirname(std::string_view entry);
// Library-specif // Library-specif
std::string getLibVersion(); std::string getLibVersion();
@@ -144,8 +147,9 @@ std::string getLibVersion();
#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_MB(x) (x / 1024) // TO_MB(2048) (2048 / 1024) #define TO_KB(x) (x / 1024) // TO_KB(1024) = 1
#define TO_GB(x) (TO_GB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 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 STYLE_RESET "\033[0m" #define STYLE_RESET "\033[0m"
#define BOLD "\033[1m" #define BOLD "\033[1m"
@@ -197,6 +201,8 @@ std::string getLibVersion();
if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__) if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__)
#define MKVERSION(name) \ #define MKVERSION(name) \
"%s %s [%s %s]\nBuildType: %s\nCMakeVersion: %s\nCompilerVersion: %s\nBuildFlags: %s\n", name, BUILD_VERSION, BUILD_DATE, BUILD_TIME, BUILD_TYPE, BUILD_CMAKE_VERSION, BUILD_COMPILER_VERSION, BUILD_FLAGS 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); \
return std::string(vinfo)
#endif // #ifndef LIBHELPER_LIB_HPP #endif // #ifndef LIBHELPER_LIB_HPP

View File

@@ -16,7 +16,6 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
@@ -30,20 +29,20 @@ bool hasSuperUser()
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);
} }
@@ -55,7 +54,7 @@ bool linkIsExists(const std::string_view 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);
} }
@@ -67,7 +66,7 @@ bool isSymbolicLink(const std::string_view 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);
} }

View File

@@ -16,11 +16,13 @@
#include <exception> #include <exception>
#include <sstream> #include <sstream>
#include <stdio.h> #include <cstdio>
#include <stdlib.h> #include <cstdlib>
#include <cstring>
#include <unistd.h> #include <unistd.h>
#include <libgen.h> #include <libgen.h>
#include <stdarg.h> #include <cstdarg>
#include <cerrno>
#include <fcntl.h> #include <fcntl.h>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
@@ -34,7 +36,7 @@ Error::Error(const char* 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) << "Error::Error(): " << _message << std::endl; LOGN(HELPER, ERROR) << _message << std::endl;
} }
const char* Error::what() const noexcept const char* Error::what() const noexcept
@@ -42,16 +44,16 @@ const char* Error::what() const noexcept
return _message.data(); return _message.data();
} }
Logger::Logger(LogLevels level, const char* func, const char* file, const char* name, const char* sfile, int line) : _level(level), _funcname(func), _logFile(file), _program_name(name), _file(sfile), _line(line) {} Logger::Logger(const LogLevels level, const char* func, const char* file, const char* name, const char* sfile, const int 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",
(char)_level, static_cast<char>(_level),
_program_name, _program_name,
basename((char*)_file), basename(const_cast<char *>(_file)),
_line, _line,
currentDate().data(), currentDate().data(),
currentTime().data(), currentTime().data(),
@@ -59,18 +61,22 @@ Logger::~Logger()
_oss.str().data()); _oss.str().data());
if (!isExists(_logFile)) { if (!isExists(_logFile)) {
remove(_logFile); if (const int fd = open(_logFile, O_WRONLY | O_CREAT, DEFAULT_EXTENDED_FILE_PERMS); fd != -1) close(fd);
int fd = open(_logFile, O_WRONLY | O_CREAT, DEFAULT_EXTENDED_FILE_PERMS); else {
if (fd != -1) close(fd); 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;
}
} }
FILE* fp = fopen(_logFile, "a"); if (FILE* fp = fopen(_logFile, "a"); fp != nullptr) {
if (fp != NULL) {
fprintf(fp, "%s", str); fprintf(fp, "%s", str);
fclose(fp); fclose(fp);
} else {
LoggingProperties::setLogFile("last_logs.log");
LOGN(HELPER, INFO) << "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\n", str); if (LoggingProperties::PRINT) printf("%s", str);
} }
Logger& Logger::operator<<(std::ostream& (*msg)(std::ostream&)) Logger& Logger::operator<<(std::ostream& (*msg)(std::ostream&))

View File

@@ -15,13 +15,12 @@
*/ */
#include <string> #include <string>
#include <stdio.h> #include <cstdio>
#include <stdlib.h> #include <cstdlib>
#include <string.h> #include <cstring>
#include <errno.h> #include <cerrno>
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h> #include <dirent.h>
#include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
@@ -29,10 +28,7 @@
static FILE* open_file(const std::string_view file, const char* mode) static FILE* open_file(const std::string_view file, const char* mode)
{ {
FILE* fp = fopen(file.data(), mode); FILE* fp = fopen(file.data(), mode);
if (fp == nullptr) { if (fp == nullptr) return nullptr;
throw Helper::Error("Cannot open %s: %s", file.data(), strerror(errno));
return fp;
}
return fp; return fp;
} }
@@ -71,37 +67,22 @@ 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." << std::endl;
int src_fd = open(file.data(), O_RDONLY); const int src_fd = open(file.data(), O_RDONLY);
if (src_fd == - 1) { if (src_fd == - 1) return false;
throw Error("Cannot open %s: %s", file.data(), strerror(errno));
return false;
}
int dst_fd = open(dest.data(), O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_PERMS); const int dst_fd = open(dest.data(), O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_PERMS);
if (dst_fd == - 1) { if (dst_fd == - 1) return false;
throw Error("Cannot create/open %s: %s", dest.data(), strerror(errno));
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) {
ssize_t bw = write(dst_fd, buffer, br); if (const ssize_t bw = write(dst_fd, buffer, br); bw != br) return false;
if (bw != br) {
throw Error("Cannot write %s: %s", dest.data(), strerror(errno));
close(src_fd);
close(dst_fd);
return false;
}
} }
close(src_fd); close(src_fd);
close(dst_fd); close(dst_fd);
if (br == -1) { if (br == -1) return false;
throw Error("Cannot read %s: %s", file.data(), strerror(errno));
return false;
}
LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " successfull." << std::endl; LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " successfull." << std::endl;
return true; return true;
@@ -111,39 +92,32 @@ 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) ? true : false; 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], *p; char tmp[PATH_MAX];
size_t len;
snprintf(tmp, sizeof(tmp), "%s", paths.data()); snprintf(tmp, sizeof(tmp), "%s", paths.data());
len = strlen(tmp); if (const size_t len = strlen(tmp); tmp[len - 1] == '/') tmp[len - 1] = '\0';
if (tmp[len - 1] == '/') tmp[len - 1] = '\0';
for (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) { && errno != EEXIST)
throw Error("Cannot create directory: %s: %s", tmp, strerror(errno)); return false;
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) { if (mkdir(tmp, DEFAULT_DIR_PERMS) != 0 && errno != EEXIST) return false;
throw Error("Cannot create directory: %s: %s", tmp, strerror(errno));
return false;
}
} }
LOGN(HELPER, INFO) << "" << paths << " successfully created." << std::endl; LOGN(HELPER, INFO) << "" << paths << " successfully created." << std::endl;
@@ -154,16 +128,10 @@ 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)) { if (isExists(path)) return false;
throw Error("%s: is exists", path.data());
return false;
}
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) { if (fd == -1) return false;
throw Error("Cannot create %s: %s", path.data(), strerror(errno));
return false;
}
close(fd); close(fd);
LOGN(HELPER, INFO) << "create file \"" << path << "\" successfull." << std::endl; LOGN(HELPER, INFO) << "create file \"" << path << "\" successfull." << std::endl;
@@ -173,38 +141,31 @@ bool createFile(const std::string_view path)
bool createSymlink(const std::string_view entry1, const std::string_view entry2) bool createSymlink(const std::string_view entry1, const std::string_view entry2)
{ {
LOGN(HELPER, INFO) << "symlink \"" << entry1 << "\" to \"" << entry2 << "\" requested." << std::endl; LOGN(HELPER, INFO) << "symlink \"" << entry1 << "\" to \"" << entry2 << "\" requested." << std::endl;
int ret = symlink(entry1.data(), entry2.data()); if (const int ret = symlink(entry1.data(), entry2.data()); ret != 0) return false;
if (ret != 0)
throw Error("Cannot symlink %s: %s", entry2.data(), strerror(errno));
LOGN_IF(HELPER, INFO, ret == 0) << "\"" << entry1 << "\" symlinked to \"" << entry2 << "\" successfully." << std::endl; LOGN(HELPER, INFO) << "\"" << entry1 << "\" symlinked to \"" << entry2 << "\" successfully." << std::endl;
return (ret == 0); 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;
int ret = remove(entry.data()); if (int ret = remove(entry.data()); ret != 0) return false;
if (ret != 0)
throw Error("Cannot remove %s: %s", entry.data(), strerror(errno));
LOGN_IF(HELPER, INFO, ret == 0) << "\"" << entry << "\" erased successfully." << std::endl; LOGN(HELPER, INFO) << "\"" << entry << "\" erased successfully." << std::endl;
return (ret == 0); 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{};
struct dirent *entry; dirent *entry;
DIR *dir = opendir(directory.data()); DIR *dir = opendir(directory.data());
if (dir == nullptr) { if (dir == nullptr) return false;
throw Error("Cannot open directory %s: %s", directory.data(), strerror(errno));
return false;
}
while ((entry = readdir(dir)) != NULL) { 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
@@ -214,7 +175,6 @@ bool eraseDirectoryRecursive(const std::string_view directory)
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) {
throw Error("Cannot stat %s: %s", fullpath, strerror(errno));
closedir(dir); closedir(dir);
return false; return false;
} }
@@ -226,7 +186,6 @@ bool eraseDirectoryRecursive(const std::string_view directory)
} }
} else { } else {
if (unlink(fullpath) == -1) { if (unlink(fullpath) == -1) {
throw Error("Cannot unlink %s: %s", fullpath, strerror(errno));
closedir(dir); closedir(dir);
return false; return false;
} }
@@ -234,10 +193,7 @@ bool eraseDirectoryRecursive(const std::string_view directory)
} }
closedir(dir); closedir(dir);
if (rmdir(directory.data()) == -1) { if (rmdir(directory.data()) == -1) return false;
throw Error("Cannot remove directory %s: %s", directory.data(), strerror(errno));
return false;
}
LOGN(HELPER, INFO) << "\"" << directory << "\" successfully erased." << std::endl; LOGN(HELPER, INFO) << "\"" << directory << "\" successfully erased." << std::endl;
return true; return true;
@@ -248,11 +204,8 @@ 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];
ssize_t len = readlink(entry.data(), target, (sizeof(target) - 1)); const ssize_t len = readlink(entry.data(), target, (sizeof(target) - 1));
if (len == -1) { if (len == -1) return entry.data();
throw Error("Cannot read symlink %s: %s", entry.data(), strerror(errno));
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 << "\"" << std::endl;
@@ -262,7 +215,7 @@ std::string readSymlink(const std::string_view entry)
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);
} }

View File

@@ -30,16 +30,9 @@ std::optional<std::string> sha256Of(const std::string_view path)
LOGN(HELPER, INFO) << "get sha256 of \"" << path << "\" request. Getting full path (if input is link and exists)." << std::endl; LOGN(HELPER, INFO) << "get sha256 of \"" << path << "\" request. Getting full path (if input is link and exists)." << std::endl;
std::string fp = (isLink(path)) ? readSymlink(path) : std::string(path); std::string fp = (isLink(path)) ? readSymlink(path) : std::string(path);
if (!fileIsExists(fp)) { if (!fileIsExists(fp)) throw Error("Is not exists or not file: %s", fp.data());
throw Error("Is not exists or not file: %s", fp.data());
return std::nullopt;
}
std::ifstream file(fp, std::ios::binary); if (const std::ifstream file(fp, std::ios::binary); !file) throw Error("Cannot open file: %s", fp.data());
if (!file) {
throw Error("Cannot open file: %s", fp.data());
return std::nullopt;
}
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());
@@ -50,8 +43,8 @@ std::optional<std::string> sha256Of(const std::string_view path)
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." << std::endl;
auto f1 = sha256Of(file1); const auto f1 = sha256Of(file1);
auto f2 = sha256Of(file2); const auto f2 = sha256Of(file2);
if (f1->empty() || f2->empty()) return false; if (f1->empty() || f2->empty()) return false;
LOGN_IF(HELPER, INFO, *f1 == *f2) << "(): input files is contains same sha256 signature." << std::endl; LOGN_IF(HELPER, INFO, *f1 == *f2) << "(): input files is contains same sha256 signature." << std::endl;
return (*f1 == *f2); return (*f1 == *f2);

View File

@@ -18,14 +18,14 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <stdio.h> #include <cstdio>
#include <stdlib.h> #include <cstdlib>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <ctime>
#include <time.h>
#include <libgen.h> #include <libgen.h>
#include <libhelper/lib.hpp> #include <libhelper/lib.hpp>
#include <generated/buildInfo.hpp> #include <generated/buildInfo.hpp>
#include <sys/stat.h>
namespace Helper { namespace Helper {
namespace LoggingProperties { namespace LoggingProperties {
@@ -78,28 +78,24 @@ bool confirmPropt(const std::string_view message)
std::cin >> p; std::cin >> p;
if (p == 'y' || p == 'Y') return true; if (p == 'y' || p == 'Y') return true;
else if (p == 'n' || p == 'N') return false; if (p == 'n' || p == 'N') return false;
else {
printf("Unexpected answer: '%c'. Try again.\n", p);
return confirmPropt(message);
}
return false; printf("Unexpected answer: '%c'. Try again.\n", p);
return confirmPropt(message);
} }
std::string currentWorkingDirectory() std::string currentWorkingDirectory()
{ {
char cwd[1024]; char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) == nullptr) return std::string(); if (getcwd(cwd, sizeof(cwd)) == nullptr) return {};
return cwd; return cwd;
} }
std::string currentDate() std::string currentDate()
{ {
time_t t = time(nullptr); const time_t t = time(nullptr);
struct tm *date = localtime(&t);
if (date) 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) + "/" +
@@ -109,10 +105,9 @@ std::string currentDate()
std::string currentTime() std::string currentTime()
{ {
time_t t = time(nullptr); const time_t t = time(nullptr);
struct tm *date = localtime(&t);
if (date) 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) + ":" +
@@ -125,10 +120,7 @@ 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) { if (!pipe) return {};
throw Error("Cannot run command: %s", cmd.data());
return {};
}
std::unique_ptr<FILE, decltype(&pclose)> pipe_holder(pipe, pclose); std::unique_ptr<FILE, decltype(&pclose)> pipe_holder(pipe, pclose);
@@ -150,31 +142,31 @@ std::string pathJoin(std::string base, std::string relative)
std::string pathBasename(const std::string_view entry) std::string pathBasename(const std::string_view entry)
{ {
if (!isExists(entry)) { char* base = basename(const_cast<char *>(entry.data()));
throw Error("No such file or directory: %s", entry.data());
return {};
}
char* base = basename((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)
{ {
if (!isExists(entry)) { char* base = dirname(const_cast<char *>(entry.data()));
throw Error("No such file or directory: %s", entry.data());
return {};
}
char* base = dirname((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)
{
LOGN(HELPER, INFO) << "change mode request: " << file << ". As mode: " << mode << std::endl;
return chmod(file.data(), mode) == 0;
}
bool changeOwner(const std::string_view file, const uid_t uid, const gid_t gid)
{
LOGN(HELPER, INFO) << "change owner request: " << file << ". As owner:group: " << uid << ":" << gid << std::endl;
return chown(file.data(), uid, gid) == 0;
}
std::string getLibVersion() std::string getLibVersion()
{ {
char vinfo[512]; MKVERSION("libhelper");
sprintf(vinfo, MKVERSION("libhelper"));
return std::string(vinfo);
} }
} // namespace Helper } // namespace Helper

View File

@@ -24,14 +24,18 @@ set(LIBPARTITION_MAP_SOURCES
# Add targets # Add targets
add_library(partition_map_shared SHARED ${LIBPARTITION_MAP_SOURCES}) add_library(partition_map_shared SHARED ${LIBPARTITION_MAP_SOURCES})
add_library(partition_map_static STATIC ${LIBPARTITION_MAP_SOURCES}) add_library(partition_map_static STATIC ${LIBPARTITION_MAP_SOURCES})
add_executable(libpartition_map_test tests/test.cpp)
# Set appropriate output names # Set appropriate output names
set_target_properties(partition_map_shared PROPERTIES OUTPUT_NAME "partition_map") set_target_properties(partition_map_shared PROPERTIES OUTPUT_NAME "partition_map")
set_target_properties(partition_map_static PROPERTIES OUTPUT_NAME "partition_map") set_target_properties(partition_map_static PROPERTIES OUTPUT_NAME "partition_map")
# Set linker flags # Set linker flags
target_link_options(libpartition_map_test PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib" "LINKER:-rpath,/data/local")
target_link_options(partition_map_shared PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") target_link_options(partition_map_shared PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
target_link_libraries(libpartition_map_test PRIVATE partition_map_shared PRIVATE helper_shared)
target_link_libraries(partition_map_shared PRIVATE helper_shared) target_link_libraries(partition_map_shared PRIVATE helper_shared)
# Build libpartition_map_test if CMAKE_BUILD_TYPE is not release
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
add_executable(libpartition_map_test ${CMAKE_CURRENT_SOURCE_DIR}/tests/test.cpp)
target_link_libraries(libpartition_map_test PRIVATE partition_map_shared PRIVATE helper_shared)
target_link_options(libpartition_map_test PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
endif()

View File

@@ -39,19 +39,17 @@ struct _entry {
}; };
/** /**
* basic_partition_map
* -------------------
* 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 { class basic_partition_map {
private: private:
void _resize_map(); void _resize_map();
int _index_of(const 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;
@@ -60,20 +58,20 @@ public:
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);
uint64_t get_size(const std::string_view name) const; [[nodiscard]] uint64_t get_size(std::string_view name) const;
bool is_logical(const std::string_view name) const; [[nodiscard]] bool is_logical(std::string_view name) const;
_returnable_entry get_all(const std::string_view name) const; [[nodiscard]] _returnable_entry get_all(std::string_view name) const;
bool find(const std::string_view name) const; [[nodiscard]] bool find(std::string_view name) const;
std::string find_(const std::string name) const; [[nodiscard]] std::string find_(const std::string& name) const;
size_t size() const; [[nodiscard]] size_t size() const;
bool empty() const; [[nodiscard]] bool empty() const;
void clear(); void clear();
basic_partition_map& operator=(const basic_partition_map& map); basic_partition_map& operator=(const basic_partition_map& map);
@@ -84,10 +82,10 @@ public:
public: public:
_entry* ptr; _entry* ptr;
iterator(_entry* p); explicit iterator(_entry* p);
auto operator*() -> std::pair<std::string&, decltype(_entry::props)&>; auto operator*() const -> std::pair<std::string&, decltype(_entry::props)&>;
_entry* operator->(); _entry* operator->() const;
iterator& operator++(); iterator& operator++();
iterator operator++(int); iterator operator++(int);
bool operator!=(const iterator& other) const; bool operator!=(const iterator& other) const;
@@ -98,7 +96,7 @@ public:
public: public:
const _entry* ptr; const _entry* ptr;
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 -> std::pair<const std::string&, const decltype(_entry::props)&>;
const _entry* operator->() const; const _entry* operator->() const;
@@ -109,13 +107,11 @@ public:
}; };
/* for-each support */ /* for-each support */
iterator begin(); [[nodiscard]] iterator begin() const;
iterator end(); [[nodiscard]] iterator end() const;
constant_iterator begin() const; [[nodiscard]] constant_iterator cbegin() const;
constant_iterator cbegin() const; [[nodiscard]] constant_iterator cend() const;
constant_iterator end() const;
constant_iterator cend() const;
}; };
using Map_t = basic_partition_map; using Map_t = basic_partition_map;
@@ -126,16 +122,14 @@ private:
std::string _workdir; std::string _workdir;
bool _any_generating_error, _map_builded; bool _any_generating_error, _map_builded;
bool _is_real_block_dir(const std::string_view path) const; [[nodiscard]] static bool _is_real_block_dir(std::string_view path);
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;
uint64_t _get_size(const std::string path); [[nodiscard]] uint64_t _get_size(const std::string& path);
public: public:
/** /**
* Default constructor
* -------------------
* 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.
@@ -143,189 +137,145 @@ public:
basic_partition_map_builder(); basic_partition_map_builder();
/** /**
* Secondary constructor * A constructor with input. Need search path
* ---------------------
* It has one arguments:
* - Directory path to search
*/ */
basic_partition_map_builder(const std::string_view path); explicit basic_partition_map_builder(std::string_view path);
/** /**
* getAll()
* --------
* 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.
*/ */
Map_t getAll() const; [[nodiscard]] Map_t getAll() const;
/** /**
* get(name)
* ---------
* WARNING: Learn about std::optional before using this function.
*
* 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.
*/ */
std::optional<std::pair<uint64_t, bool>> get(const std::string_view name) const; [[nodiscard]] std::optional<std::pair<uint64_t, bool>> get(std::string_view name) const;
/** /**
* getLogicalPartitionList()
* -------------------------
* WARNING: Learn about std::optional before using this function.
*
* 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.
*/ */
std::optional<std::list<std::string>> getLogicalPartitionList() const; [[nodiscard]] std::optional<std::list<std::string>> getLogicalPartitionList() const;
/** /**
* getPhysicalPartitionList()
* --------------------------
* WARNING: Learn about std::optional before using this function.
*
* 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.
*/ */
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
* If there is no content due to any problem, returns std::nullopt
*/
[[nodiscard]] std::optional<std::list<std::string>> getPartitionList() const;
/** /**
* getRealLinkPathOf(name)
* -----------------------
* WARNING: Learn about std::optional before using this function.
*
* 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.
*/ */
std::string getRealLinkPathOf(const std::string_view name) const; [[nodiscard]] std::string getRealLinkPathOf(std::string_view name) const;
/** /**
* getRealPathOf(name)
* -------------------
* WARNING: Learn about std::optional before using this function.
*
* 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
*/ */
std::string getRealPathOf(const std::string_view name) const; [[nodiscard]] std::string getRealPathOf(std::string_view name) const;
/** /**
* getCurrentWorkDir()
* -------------------
* WARNING: Learn about std::optional before using this function.
*
* 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.
*/ */
std::string getCurrentWorkDir() const; [[nodiscard]] std::string getCurrentWorkDir() const;
/** /**
* hasPartition(name)
* ------------------
* 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.
*/ */
bool hasPartition(const std::string_view name) const; [[nodiscard]] bool hasPartition(std::string_view name) const;
/** /**
* isLogical(name)
* ---------------
* Returns the bool type status of whether the * Returns the bool type status of whether the
* entered section name is marked as logical in the * entered partition name is marked as logical in the
* created list. Alternatively, the current section * 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.
*/ */
bool isLogical(const std::string_view name) const; [[nodiscard]] bool isLogical(std::string_view name) const;
/** /**
* clear()
* -------
* 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();
/** /**
* readDirectory(path)
* -------------------
* 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(const std::string_view path); bool readDirectory(std::string_view path);
/**
* Reads default /dev entries and builds map.
*/
bool readDefaultDirectories();
/** /**
* empty()
* -------
* 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.
*/ */
bool empty() const; [[nodiscard]] bool empty() const;
/** /**
* sizeOf(name)
* ------------
* WARNING: Learn about std::optional before using this function.
*
* 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.
*/ */
uint64_t sizeOf(const std::string_view name) const; [[nodiscard]] uint64_t sizeOf(std::string_view name) const;
/** /**
* == operator
* -----------
* 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==(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs); friend bool operator==(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs);
/** /**
* != operator
* -----------
* The opposite logic of the == operator. * The opposite logic of the == operator.
*/ */
friend bool operator!=(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs); friend bool operator!=(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs);
/** /**
* Boolean operator
* ----------------
* 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.
*/ */
operator bool() const; explicit operator bool() const;
/** /**
* ! operator
* ----------
* 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;
/** /**
* () operator
* -----------
* Build map with input path. Implementation of readDirectory(). * Build map with input path. Implementation of readDirectory().
*/ */
bool operator()(const std::string_view path); bool operator()(std::string_view path);
}; };
using Error = Helper::Error; using Error = Helper::Error;
/** /**
* getLibVersion()
* ---------------
* 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.
*/ */

View File

@@ -59,6 +59,16 @@ std::optional<std::list<std::string>> basic_partition_map_builder::getPhysicalPa
return physicals; return physicals;
} }
std::optional<std::list<std::string>> basic_partition_map_builder::getPartitionList() const {
_map_build_check();
std::list<std::string> partitions;
for (const auto& [name, props] : _current_map) partitions.push_back(name);
if (partitions.empty()) return std::nullopt;
return partitions;
}
std::string basic_partition_map_builder::getRealLinkPathOf(const std::string_view name) const std::string basic_partition_map_builder::getRealLinkPathOf(const std::string_view name) const
{ {
_map_build_check(); _map_build_check();

View File

@@ -18,19 +18,18 @@
#include <vector> #include <vector>
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <vector>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <errno.h> #include <cerrno>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
#include <generated/buildInfo.hpp> #include <generated/buildInfo.hpp>
#include <string.h> #include <cstring>
#include <unistd.h> #include <unistd.h>
static constexpr std::array<std::string_view, 3> defaultEntryList = { static constexpr std::array<std::string_view, 3> defaultEntryList = {
@@ -41,9 +40,12 @@ static constexpr std::array<std::string_view, 3> defaultEntryList = {
namespace PartitionMap { namespace PartitionMap {
bool basic_partition_map_builder::_is_real_block_dir(const std::string_view path) const bool basic_partition_map_builder::_is_real_block_dir(const std::string_view path)
{ {
if (path.find("/block/") == std::string::npos) return false; if (path.find("/block/") == std::string::npos) {
LOGN(MAP, ERROR) << "Path " << path << " is not a real block directory.";
return false;
}
return true; return true;
} }
@@ -68,6 +70,7 @@ Map_t basic_partition_map_builder::_build_map(std::string_view path, bool logica
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;
_current_map.merge(logicals); _current_map.merge(logicals);
} }
@@ -77,10 +80,10 @@ void basic_partition_map_builder::_map_build_check() const
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)
{ {
std::string real = std::filesystem::read_symlink(path); const std::string real = std::filesystem::read_symlink(path);
int fd = open(real.data(), O_RDONLY); const int fd = open(real.data(), 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) << std::endl;
return 0; return 0;
@@ -106,7 +109,6 @@ basic_partition_map_builder::basic_partition_map_builder()
_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;
continue;
} else { } else {
_workdir = path; _workdir = path;
break; break;
@@ -127,7 +129,7 @@ basic_partition_map_builder::basic_partition_map_builder(const std::string_view
LOGN(MAP, INFO) << "argument-based constructor called. Starting build." << std::endl; LOGN(MAP, INFO) << "argument-based constructor called. Starting build." << std::endl;
if (std::filesystem::exists(path)) { if (std::filesystem::exists(path)) {
_is_real_block_dir(path); 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;
@@ -179,6 +181,33 @@ bool basic_partition_map_builder::readDirectory(const std::string_view path)
return true; return true;
} }
bool basic_partition_map_builder::readDefaultDirectories()
{
_map_builded = false;
LOGN(MAP, INFO) << "read default directories request." << std::endl;
for (const auto& path : defaultEntryList) {
if (std::filesystem::exists(path)) {
_current_map = _build_map(path);
if (_current_map.empty()) {
_any_generating_error = true;
return false;
} else {
_workdir = path;
break;
}
}
}
if (_current_map.empty())
LOGN(MAP, ERROR) << "Cannot build map by any default search entry." << std::endl;
LOGN(MAP, INFO) << "read default directories successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
return true;
}
bool basic_partition_map_builder::empty() const bool basic_partition_map_builder::empty() const
{ {
_map_build_check(); _map_build_check();
@@ -191,12 +220,12 @@ uint64_t basic_partition_map_builder::sizeOf(const std::string_view name) const
return _current_map.get_size(name); return _current_map.get_size(name);
} }
bool operator==(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs) bool operator==(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs)
{ {
return lhs._current_map == rhs._current_map; return lhs._current_map == rhs._current_map;
} }
bool operator!=(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs) bool operator!=(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
@@ -219,9 +248,7 @@ bool basic_partition_map_builder::operator()(const std::string_view path)
std::string getLibVersion() std::string getLibVersion()
{ {
char vinfo[512]; MKVERSION("libpartition_map");
sprintf(vinfo, MKVERSION("libpartition_map"));
return std::string(vinfo);
} }
} // namespace PartitionMap } // namespace PartitionMap

View File

@@ -23,12 +23,12 @@ 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*() -> std::pair<std::string&, decltype(_entry::props)&> auto basic_partition_map::iterator::operator*() const -> std::pair<std::string&, decltype(_entry::props)&>
{ {
return {ptr->name, ptr->props}; return {ptr->name, ptr->props};
} }
_entry* basic_partition_map::iterator::operator->() _entry* basic_partition_map::iterator::operator->() const
{ {
return ptr; return ptr;
} }
@@ -41,17 +41,17 @@ basic_partition_map::iterator& basic_partition_map::iterator::operator++()
basic_partition_map::iterator basic_partition_map::iterator::operator++(int) basic_partition_map::iterator basic_partition_map::iterator::operator++(int)
{ {
basic_partition_map::iterator tmp = *this; iterator tmp = *this;
++ptr; ++ptr;
return tmp; return tmp;
} }
bool basic_partition_map::iterator::operator==(const basic_partition_map::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 basic_partition_map::iterator& other) const bool basic_partition_map::iterator::operator!=(const iterator& other) const
{ {
return ptr != other.ptr; return ptr != other.ptr;
} }
@@ -76,25 +76,25 @@ basic_partition_map::constant_iterator& basic_partition_map::constant_iterator::
basic_partition_map::constant_iterator basic_partition_map::constant_iterator::operator++(int) basic_partition_map::constant_iterator basic_partition_map::constant_iterator::operator++(int)
{ {
basic_partition_map::constant_iterator tmp = *this; constant_iterator tmp = *this;
++ptr; ++ptr;
return tmp; return tmp;
} }
bool basic_partition_map::constant_iterator::operator==(const basic_partition_map::constant_iterator& other) const bool basic_partition_map::constant_iterator::operator==(const constant_iterator& other) const
{ {
return ptr == other.ptr; return ptr == other.ptr;
} }
bool basic_partition_map::constant_iterator::operator!=(const basic_partition_map::constant_iterator& other) const bool basic_partition_map::constant_iterator::operator!=(const constant_iterator& other) const
{ {
return ptr != other.ptr; return ptr != other.ptr;
} }
void basic_partition_map::_resize_map() void basic_partition_map::_resize_map()
{ {
size_t new_capacity = _capacity * 2; const size_t new_capacity = _capacity * 2;
_entry* new_data = new _entry[new_capacity]; auto* new_data = new _entry[new_capacity];
for (size_t i = 0; i < _count; i++) new_data[i] = _data[i]; for (size_t i = 0; i < _count; i++) new_data[i] = _data[i];
@@ -106,13 +106,13 @@ void basic_partition_map::_resize_map()
int basic_partition_map::_index_of(const std::string_view name) const int basic_partition_map::_index_of(const std::string_view name) const
{ {
for (size_t i = 0; i < _count; i++) { for (size_t i = 0; i < _count; i++) {
if (name == _data[i].name) return (int)i; if (name == _data[i].name) return static_cast<int>(i);
} }
return 0; return 0;
} }
basic_partition_map::basic_partition_map(const std::string name, uint64_t size, bool logical) basic_partition_map::basic_partition_map(const std::string& name, const uint64_t size, const bool logical)
{ {
_data = new _entry[_capacity]; _data = new _entry[_capacity];
insert(name, size, logical); insert(name, size, logical);
@@ -126,7 +126,7 @@ basic_partition_map::basic_partition_map(const basic_partition_map& other) :
std::copy(other._data, other._data + _count, _data); std::copy(other._data, other._data + _count, _data);
} }
basic_partition_map::basic_partition_map() : _count(0), _capacity(6) basic_partition_map::basic_partition_map() : _capacity(6)
{ {
_data = new _entry[_capacity]; _data = new _entry[_capacity];
} }
@@ -136,7 +136,7 @@ basic_partition_map::~basic_partition_map()
delete[] _data; delete[] _data;
} }
bool basic_partition_map::insert(const std::string name, uint64_t size, bool logical) bool basic_partition_map::insert(const std::string& name, const uint64_t size, const bool logical)
{ {
if (name == _data[_index_of(name)].name) return false; if (name == _data[_index_of(name)].name) return false;
if (_count == _capacity) _resize_map(); if (_count == _capacity) _resize_map();
@@ -186,7 +186,7 @@ bool basic_partition_map::find(const std::string_view name) const
return false; return false;
} }
std::string basic_partition_map::find_(const std::string name) const std::string basic_partition_map::find_(const std::string& name) const
{ {
if (name == _data[_index_of(name)].name) return name; if (name == _data[_index_of(name)].name) return name;
@@ -249,34 +249,24 @@ bool basic_partition_map::operator!=(const basic_partition_map& other) const
return !(*this == other); return !(*this == other);
} }
basic_partition_map::iterator basic_partition_map::begin() basic_partition_map::iterator basic_partition_map::begin() const
{ {
return basic_partition_map::iterator(_data); return iterator(_data);
} }
basic_partition_map::iterator basic_partition_map::end() basic_partition_map::iterator basic_partition_map::end() const
{ {
return basic_partition_map::iterator(_data + _count); return iterator(_data + _count);
}
basic_partition_map::constant_iterator basic_partition_map::begin() const
{
return basic_partition_map::constant_iterator(_data);
} }
basic_partition_map::constant_iterator basic_partition_map::cbegin() const basic_partition_map::constant_iterator basic_partition_map::cbegin() const
{ {
return basic_partition_map::constant_iterator(_data); return constant_iterator(_data);
}
basic_partition_map::constant_iterator basic_partition_map::end() const
{
return basic_partition_map::constant_iterator(_data + _count);
} }
basic_partition_map::constant_iterator basic_partition_map::cend() const basic_partition_map::constant_iterator basic_partition_map::cend() const
{ {
return basic_partition_map::constant_iterator(_data + _count); return constant_iterator(_data + _count);
} }
} // namespace PartitionMap } // namespace PartitionMap

View File

@@ -18,7 +18,7 @@
#include <unistd.h> #include <unistd.h>
#include <libpartition_map/lib.hpp> #include <libpartition_map/lib.hpp>
int main(void) { int main() {
if (getuid() != 0) return 2; if (getuid() != 0) return 2;
try { try {
@@ -28,7 +28,7 @@ int main(void) {
if (!MyMap) throw PartitionMap::Error("Cannot generate object!"); if (!MyMap) throw PartitionMap::Error("Cannot generate object!");
} }
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: "
@@ -36,19 +36,19 @@ int main(void) {
<< props.isLogical << std::endl; << props.isLogical << std::endl;
} }
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 << ", logical: " << boot->first << ", logical: "
<< boot->second << std::endl; << boot->second << std::endl;
auto logicals = MyMap.getLogicalPartitionList(); const auto logicals = MyMap.getLogicalPartitionList();
if (!logicals) throw PartitionMap::Error("getLogicalPartitionList() returned nullopt"); if (!logicals) throw PartitionMap::Error("getLogicalPartitionList() returned nullopt");
std::cout << "Logical partitions: " << std::endl; std::cout << "Logical partitions: " << std::endl;
for (const auto& name : *logicals) for (const auto& name : *logicals)
std::cout << " - " << name << std::endl; std::cout << " - " << name << std::endl;
auto physicals = MyMap.getPhysicalPartitionList(); const auto physicals = MyMap.getPhysicalPartitionList();
if (!physicals) throw PartitionMap::Error("getPhysicalPartitionList() returned nullopt"); if (!physicals) throw PartitionMap::Error("getPhysicalPartitionList() returned nullopt");
std::cout << "Physical partitions: " << std::endl; std::cout << "Physical partitions: " << std::endl;
for (const auto& name : *physicals) for (const auto& name : *physicals)

View File