pmt: New features and improvements

- Added type getter and reboot function
 - Writed a garbage collector, so manually freeing memory and closing file descriptors is removed
 - Some other improvements
This commit is contained in:
2025-08-09 12:48:04 +03:00
parent 8b3e886eee
commit 8e629d60d0
28 changed files with 1826 additions and 1265 deletions

View File

@@ -18,7 +18,6 @@
#define LIBPMT_LIB_HPP
#include <string>
#include <string_view>
#include <vector>
#include <memory>
#include <libhelper/lib.hpp>
@@ -59,13 +58,7 @@ namespace PartitionManager {
[[nodiscard]] bool handleAll() const;
};
// Sets logs file automatically
class logSetter final { public: logSetter(); };
class basic_variables final {
private:
logSetter setLogSetting;
public:
basic_variables();
~basic_variables();
@@ -80,6 +73,17 @@ namespace PartitionManager {
bool forceProcess;
};
class variableProtect final {
private:
basic_variables* _ptr = nullptr;
public:
variableProtect();
~variableProtect();
void setVariablePointer(basic_variables* &_ptr);
};
using FunctionBase = basic_function;
using FunctionManager = basic_function_manager;
using VariableTable = basic_variables;
@@ -92,8 +96,10 @@ namespace PartitionManager {
// Print messages if not using quiet mode
__attribute__((format(printf, 1, 2)))
void print(const char *format, ...);
__attribute__((format(printf, 1, 2)))
void println(const char *format, ...);
// Format it input and return
// Format it input and return as std::string
__attribute__((format(printf, 1, 2)))
std::string format(const char *format, ...);

View File

@@ -25,6 +25,8 @@ set(PMT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/functions/PartitionSizeFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealPathFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealLinkPathFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/RebootFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/TypeFunction.cpp
)
# Add pmt

View File

@@ -14,6 +14,7 @@
limitations under the License.
*/
#include <fcntl.h>
#include <vector>
#include <memory>
#include <string>
@@ -69,7 +70,7 @@ namespace PartitionManager {
}
LOGN(PMTF, INFO) << "not found any used function from command-line." << std::endl;
print("Target progress is not specified. Specify a progress.");
println("Target progress is not specified. Specify a progress.");
return false;
}
} // namespace PartitionManager

View File

@@ -18,17 +18,20 @@
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include <generated/buildInfo.hpp>
#include "functions/functions.hpp"
namespace PartitionManager {
variableProtect protector;
auto Variables = new VariableTable();
logSetter::logSetter() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); }
variableProtect::variableProtect() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); }
variableProtect::~variableProtect() { delete _ptr; }
void variableProtect::setVariablePointer(basic_variables *&_ptr) { this->_ptr = _ptr; }
basic_variables::~basic_variables() { delete PartMap; }
basic_variables::basic_variables() : PartMap(new PartitionMap::BuildMap()),
logFile("/sdcard/Documents/last_pmt_logs.log"),
onLogical(false),
@@ -42,10 +45,11 @@ namespace PartitionManager {
try {
// try-catch start
CLI::App AppMain{"Partition Manager Tool"};
protector.setVariablePointer(Variables);
FunctionManager FuncManager;
AppMain.fallthrough(true);
AppMain.set_help_all_flag("--help-all", "Print full help message");
AppMain.set_help_all_flag("--help-all", "Print full help message and exit");
AppMain.footer("Partition Manager Tool is written by YZBruh\nThis project licensed under Apache 2.0 license\nReport bugs to https://github.com/ShawkTeam/pmt-renovated/issues");
AppMain.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check(
[&](const std::string &val) {
@@ -62,7 +66,7 @@ namespace PartitionManager {
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]);
println("Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.", argv[0]);
return EXIT_FAILURE;
}
@@ -73,34 +77,29 @@ namespace PartitionManager {
FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<realPathFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<realLinkPathFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<typeFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<rebootFunction>(), 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->viewVersion) { println("%s", getAppVersion().data()); return EXIT_SUCCESS; }
if (!Variables->searchPath.empty()) (*Variables->PartMap)(Variables->searchPath);
if (!Variables->PartMap && Variables->searchPath.empty())
throw Error("No default search entries were found. Specify a search directory with -S (--search-path)");
if (!Helper::hasSuperUser()) throw Error("This program requires super-user privileges!");
if (!Helper::hasSuperUser()) throw Error("Partition Manager Tool is requires super-user privileges!\n");
return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE;
} catch (Helper::Error &error) {
// catch Helper::Error
if (!Variables->quietProcess) fprintf(stderr, "%s%sERROR(S) OCCURRED%s:\n%s", RED, BOLD, STYLE_RESET,
error.what());
delete Variables;
if (!Variables->quietProcess) fprintf(stderr, "%s%sERROR(S) OCCURRED:%s\n%s", RED, BOLD, STYLE_RESET, error.what());
return EXIT_FAILURE;
} catch (CLI::Error &error) {
// catch CLI::Error
delete Variables;
fprintf(stderr, "%s: %s%sFLAG PARSE ERROR:%s %s\n", argv[0], RED, BOLD, STYLE_RESET, error.what());
return EXIT_FAILURE;
} // try-catch block end
@@ -113,6 +112,13 @@ namespace PartitionManager {
va_end(args);
}
void println(const char *format, ...) {
va_list args;
va_start(args, format);
if (!Variables->quietProcess) { vfprintf(stdout, format, args); print("\n"); }
va_end(args);
}
std::string format(const char *format, ...) {
va_list args;
va_start(args, format);

View File

@@ -21,6 +21,7 @@
#include <future>
#include <chrono>
#include <PartitionManager/PartitionManager.hpp>
#include <private/android_filesystem_config.h>
#include "functions.hpp"
#define BFUN "backupFunction"
@@ -37,9 +38,7 @@ namespace PartitionManager {
if (Variables->forceProcess)
LOGN(BFUN, WARNING) << "Partition " << partitionName <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else return {
format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false
};
else return {format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false};
}
if (Helper::fileIsExists(outputName) && !Variables->forceProcess) return {
@@ -49,32 +48,30 @@ namespace PartitionManager {
setupBufferSize(bufferSize, partitionName);
LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName << "): " << bufferSize << std::endl;
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDONLY);
// Automatically close file descriptors and delete allocated memories (arrays)
Helper::garbageCollector collector;
const int pfd = Helper::openAndAddToCloseList(Variables->PartMap->getRealPathOf(partitionName), collector, O_RDONLY);
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
const int ffd = open(outputName.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ffd < 0) {
close(pfd);
return {format("Can't create/open output file %s: %s", outputName.data(), strerror(errno)), false};
}
const int ffd = Helper::openAndAddToCloseList(outputName, collector, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ffd < 0) return {format("Can't create/open output file %s: %s", outputName.data(), strerror(errno)), false};
LOGN(BFUN, INFO) << "Writing partition " << partitionName << " to file: " << outputName << std::endl;
auto *buffer = new char[bufferSize];
collector.delAfterProgress(buffer);
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;
return {
format("Can't write partition to output file %s: %s", outputName.data(), strerror(errno)), false
};
}
if (const ssize_t bytesWritten = write(ffd, buffer, bytesRead); bytesWritten != bytesRead)
return {format("Can't write partition to output file %s: %s", outputName.data(), strerror(errno)), false};
}
close(pfd);
close(ffd);
delete[] buffer;
if (!Helper::changeOwner(outputName, AID_EVERYBODY, AID_EVERYBODY))
LOGN(BFUN, WARNING) << "Failed to change owner of output file: " << outputName << ". Access problems maybe occur in non-root mode" << std::endl;
if (!Helper::changeMode(outputName, 0660))
LOGN(BFUN, WARNING) << "Failed to change mode of output file as 660: " << outputName << ". Access problems maybe occur in non-root mode" << std::endl;
return {format("%s partition successfully back upped to %s", partitionName.data(), outputName.data()), true};
}
@@ -84,8 +81,7 @@ namespace PartitionManager {
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required();
cmd->add_option("output(s)", rawOutputNames, "File name(s) (or path(s)) to save the partition image(s)");
cmd->add_option("-O,--output-directory", outputDirectory, "Directory to save the partition image(s)")->check(
CLI::ExistingDirectory);
cmd->add_option("-O,--output-directory", outputDirectory, "Directory to save the partition image(s)")->check(CLI::ExistingDirectory);
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading partition(s) and writing to file(s)");
return true;
@@ -111,7 +107,7 @@ namespace PartitionManager {
for (auto &future: futures) {
auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; }
else print("%s\n", fst.c_str());
else println("%s", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());

View File

@@ -34,15 +34,16 @@ namespace PartitionManager {
if (Variables->forceProcess)
LOGN(EFUN, WARNING) << "Partition " << partitionName <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else return {
format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false
};
else return {format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false};
}
setupBufferSize(bufferSize, partitionName);
LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize;
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_WRONLY);
// Automatically close file descriptors and delete allocated memories (arrays)
Helper::garbageCollector collector;
const int pfd = Helper::openAndAddToCloseList(Variables->PartMap->getRealPathOf(partitionName), collector, O_WRONLY);
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
if (!Variables->forceProcess) Helper::confirmPropt(
@@ -50,7 +51,9 @@ namespace PartitionManager {
LOGN(EFUN, INFO) << "Writing zero bytes to partition: " << partitionName << std::endl;
auto *buffer = new char[bufferSize];
collector.delAfterProgress(buffer);
memset(buffer, 0x00, bufferSize);
ssize_t bytesWritten = 0;
const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName);
@@ -58,18 +61,11 @@ namespace PartitionManager {
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;
return {
format("Can't write zero bytes to partition: %s: %s", partitionName.data(), strerror(errno)), false
};
} else bytesWritten += result;
if (const ssize_t result = write(pfd, buffer, toWrite); result == -1)
return {format("Can't write zero bytes to partition: %s: %s", partitionName.data(), strerror(errno)), false};
else bytesWritten += result;
}
close(pfd);
delete[] buffer;
return {format("Successfully wrote zero bytes to the %s partition\n", partitionName.data()), true};
}
@@ -93,7 +89,7 @@ namespace PartitionManager {
for (auto &future: futures) {
auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; }
else print("%s\n", fst.c_str());
else println("%s", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());

View File

@@ -27,9 +27,9 @@ Copyright 2025 Yağız Zengin
namespace PartitionManager {
pair flashFunction::runAsync(const std::string &partitionName, const std::string &imageName, int bufferSize) {
if (!Helper::fileIsExists(imageName)) return {format("Couldn't find image file: %s", imageName.data()), false};
if (!Variables->PartMap->hasPartition(partitionName)) return {
format("Couldn't find partition: %s", partitionName.data()), false
};
if (!Variables->PartMap->hasPartition(partitionName)) return {format("Couldn't find partition: %s", partitionName.data()), false};
if (Helper::fileSize(imageName) > Variables->PartMap->sizeOf(partitionName))
return {format("%s is larger than %s partition size!", imageName.data(), partitionName.data()), false};
LOGN(FFUN, INFO) << "flashing " << imageName << " to " << partitionName << std::endl;
@@ -45,35 +45,27 @@ namespace PartitionManager {
setupBufferSize(bufferSize, imageName);
LOGN(FFUN, INFO) << "Using buffer size: " << bufferSize;
const int ffd = open(imageName.data(), O_RDONLY);
// Automatically close file descriptors and delete allocated memories (arrays)
Helper::garbageCollector collector;
const int ffd = Helper::openAndAddToCloseList(imageName, collector, O_RDONLY);
if (ffd < 0) return {format("Can't open image file %s: %s", imageName.data(), strerror(errno)), false};
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDWR | O_TRUNC);
if (pfd < 0) {
close(ffd);
return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
}
const int pfd = Helper::openAndAddToCloseList(Variables->PartMap->getRealPathOf(partitionName), collector, O_RDWR | O_TRUNC);
if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
LOGN(FFUN, INFO) << "Writing image " << imageName << " to partition: " << partitionName << std::endl;
auto *buffer = new char[bufferSize];
collector.delAfterProgress(buffer);
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;
return {
format("Can't write partition to output file %s: %s", imageName.data(), strerror(errno)), false
};
}
if (const ssize_t bytesWritten = write(pfd, buffer, bytesRead); bytesWritten != bytesRead)
return {format("Can't write partition to output file %s: %s", imageName.data(), strerror(errno)), false};
}
close(pfd);
close(ffd);
delete[] buffer;
return {format("%s is successfully wrote to %s partition\n", imageName.data(), partitionName.data()), true};
return {format("%s is successfully wrote to %s partition", imageName.data(), partitionName.data()), true};
}
bool flashFunction::init(CLI::App &_app) {
@@ -108,7 +100,7 @@ namespace PartitionManager {
if (!snd) {
end += fst + '\n';
endResult = false;
} else print("%s", fst.c_str());
} else println("%s", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());

View File

@@ -60,9 +60,9 @@ namespace PartitionManager {
if (jsonFormat)
#ifdef __LP64__
print("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}\n",
println("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}",
#else
print("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}\n",
println("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}",
#endif
jNamePartition.data(),
partition.data(),
@@ -72,9 +72,9 @@ namespace PartitionManager {
Variables->PartMap->isLogical(partition) ? "true" : "false");
else
#ifdef __LP64__
print("partition=%s size=%lu isLogical=%s\n",
println("partition=%s size=%lu isLogical=%s",
#else
print("partition=%s size=%llu isLogical=%s\n",
println("partition=%s size=%llu isLogical=%s",
#endif
partition.data(),
Variables->PartMap->sizeOf(partition),

View File

@@ -57,7 +57,7 @@ namespace PartitionManager {
if (asMega) multiple = "MB";
if (asGiga) multiple = "GB";
print("%s: %s%s\n", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(),
println("%s: %s%s", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(),
multiple.data());
}

View File

@@ -39,7 +39,7 @@ namespace PartitionManager {
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data());
}
print("%s\n", Variables->PartMap->getRealPathOf(partition).data());
println("%s", Variables->PartMap->getRealPathOf(partition).data());
}
return true;

View File

@@ -39,7 +39,7 @@ namespace PartitionManager {
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data());
}
print("%s\n", Variables->PartMap->getRealPathOf(partition).data());
println("%s", Variables->PartMap->getRealPathOf(partition).data());
}
return true;

View File

@@ -0,0 +1,42 @@
/*
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 RFUN "rebootFunction"
namespace PartitionManager {
bool rebootFunction::init(CLI::App &_app) {
LOGN(RFUN, INFO) << "Initializing variables of reboot function." << std::endl;
cmd = _app.add_subcommand("reboot", "Reboots device");
cmd->add_option("rebootTarget", rebootTarget, "Reboot target (default: normal)");
return true;
}
bool rebootFunction::run() {
LOGN(RFUN, INFO) << "Rebooting device!!! (custom reboot target: " << (rebootTarget.empty() ? "none" : rebootTarget) << std::endl;
if (Helper::reboot(rebootTarget)) println("Reboot command was sent");
else throw Error("Cannot reboot device");
return true;
}
bool rebootFunction::isUsed() const { return cmd->parsed(); }
const char* rebootFunction::name() const { return RFUN; }
} // namespace PartitionManager

View File

@@ -0,0 +1,62 @@
/*
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 TFUN "typeFunction"
namespace PartitionManager {
bool typeFunction::init(CLI::App &_app) {
LOGN(TFUN, INFO) << "Initializing variables of type function." << std::endl;
cmd = _app.add_subcommand("type", "Get type of the partition(s) or image(s)");
cmd->add_option("content(s)", contents, "Content(s)")->required()->delimiter(',');
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for max seek depth");
cmd->add_flag("--only-check-android-magics", onlyCheckAndroidMagics, "Only check Android magic values.");
cmd->add_flag("--only-check-filesystem-magics", onlyCheckFileSystemMagics, "Only check filesystem magic values.");
return true;
}
bool typeFunction::run() {
std::unordered_map<uint64_t, std::string> magics;
if (onlyCheckAndroidMagics) magics.merge(PartitionMap::Extras::AndroidMagicMap);
else if (onlyCheckFileSystemMagics) magics.merge(PartitionMap::Extras::FileSystemMagicMap);
else magics.merge(PartitionMap::Extras::MagicMap);
for (const auto& content : contents) {
if (!Variables->PartMap->hasPartition(content) && !Helper::fileIsExists(content))
throw Error("Couldn't find partition or image file: %s\n", content.data());
bool found = false;
for (const auto& [magic, name] : magics) {
if (PartitionMap::Extras::hasMagic(magic, bufferSize, Helper::fileIsExists(content) ? content : Variables->PartMap->getRealPathOf(content))) {
println("%s contains %s magic (%s)", content.data(), name.data(), PartitionMap::Extras::formatMagic(magic).data());
found = true;
break;
}
}
if (!found) throw Error("Couldn't determine type of %s%s\n", content.data(), content == "userdata" ? " (encrypted file system?)" : "");
}
return true;
}
bool typeFunction::isUsed() const { return cmd->parsed(); }
const char* typeFunction::name() const { return TFUN; }
} // namespace PartitionManager

View File

@@ -137,6 +137,36 @@ namespace PartitionManager {
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
};
class typeFunction final : public FunctionBase {
private:
std::vector<std::string> contents;
bool onlyCheckAndroidMagics = false, onlyCheckFileSystemMagics = false;
int bufferSize = 4096;
public:
CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override;
bool run() override;
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
};
class rebootFunction final : public FunctionBase {
private:
std::string rebootTarget;
public:
CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override;
bool run() override;
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
};
} // namespace PartitionManager
#endif // #ifndef FUNCTIONS_HPP

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2011, The Android Open Source Project
*
* 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.
*/
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
/* Commands */
#define ANDROID_RB_RESTART 0xDEAD0001 /* deprecated. Use RESTART2. */
#define ANDROID_RB_POWEROFF 0xDEAD0002
#define ANDROID_RB_RESTART2 0xDEAD0003
#define ANDROID_RB_THERMOFF 0xDEAD0004
/* Properties */
#define ANDROID_RB_PROPERTY "sys.powerctl"
/* Android reboot reason stored in this property */
#define LAST_REBOOT_REASON_PROPERTY "persist.sys.boot.reason"
#define LAST_REBOOT_REASON_FILE "/metadata/bootstat/" LAST_REBOOT_REASON_PROPERTY
/* Reboot or shutdown the system.
* This call uses ANDROID_RB_PROPERTY to request reboot to init process.
* Due to that, process calling this should have proper selinux permission
* to write to the property or the call will fail.
*/
int android_reboot(unsigned cmd, int flags, const char* arg);
__END_DECLS

View File

@@ -17,6 +17,7 @@
#ifndef LIBHELPER_LIB_HPP
#define LIBHELPER_LIB_HPP
#include <cstdint>
#include <string>
#include <string_view>
#include <sstream>
@@ -39,7 +40,6 @@ constexpr int YES = 1;
constexpr int NO = 0;
namespace Helper {
// Logging
class Logger final {
private:
@@ -50,14 +50,15 @@ private:
public:
Logger(LogLevels level, const char *func, const char *file, const char *name, const char *sfile, int line);
~Logger();
template<typename T>
Logger& operator<<(const T& msg)
{
Logger &operator<<(const T &msg) {
_oss << msg;
return *this;
}
Logger &operator<<(std::ostream & (*msg)(std::ostream &));
};
@@ -73,8 +74,24 @@ public:
[[nodiscard]] const char *what() const noexcept override;
};
namespace LoggingProperties {
// Close file descriptors and delete allocated array memory
class garbageCollector {
private:
std::vector<char*> _ptrs_c;
std::vector<uint8_t*> _ptrs_u;
std::vector<FILE*> _fps;
std::vector<int> _fds;
public:
~garbageCollector();
void delAfterProgress(char* &_ptr);
void delAfterProgress(uint8_t* &_ptr);
void delAfterProgress(FILE* &_fp);
void closeAfterProgress(int _fd);
};
namespace LoggingProperties {
extern std::string_view FILE, NAME;
extern bool PRINT, DISABLE;
@@ -83,8 +100,8 @@ void setProgramName(std::string_view name);
void setLogFile(std::string_view file);
void setPrinting(int state);
void setLoggingState(int state); // Disable/enable logging
void reset();
void reset();
} // namespace LoggingProperties
// Checkers
@@ -134,9 +151,16 @@ std::string pathJoin(std::string base, std::string relative);
std::string pathBasename(std::string_view entry);
std::string pathDirname(std::string_view entry);
// Android
std::string getProperty(std::string_view prop);
bool reboot(std::string_view arg);
// Library-specif
std::string getLibVersion();
// Open input path with flags and add to integrity list. And return file descriptor
[[nodiscard]] int openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, int flags, mode_t mode = 0000);
[[nodiscard]] FILE* openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, const char* mode);
} // namespace Helper
#endif // #ifndef ONLY_HELPER_MACROS

View File

@@ -0,0 +1,246 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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.
*/
/*
* This file is consumed by build/tools/fs_config and is used
* for generating various files. Anything #define AID_<name>
* becomes the mapping for getpwnam/getpwuid, etc. The <name>
* field is lowercased.
* For example:
* #define AID_FOO_BAR 6666 becomes a friendly name of "foo_bar"
*
* The above holds true with the exception of:
* mediacodec
* mediaex
* mediadrm
* Whose friendly names do not match the #define statements.
*
* This file must only be used for platform (Google managed, and submitted through AOSP), AIDs. 3rd
* party AIDs must be added via config.fs, which will place them in the corresponding partition's
* passwd and group files. There are ranges in this file reserved for AIDs for each 3rd party
* partition, from which the system reads passwd and group files.
*/
#pragma once
/* This is the main Users and Groups config for the platform.
* DO NOT EVER RENUMBER
*/
#define AID_ROOT 0 /* traditional unix root user */
/* The following are for tests like LTP and should only be used for testing. */
#define AID_DAEMON 1 /* Traditional unix daemon owner. */
#define AID_BIN 2 /* Traditional unix binaries owner. */
#define AID_SYS 3 /* A group with the same gid on Linux/macOS/Android. */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define AID_ADB 1011 /* android debug bridge (adbd) */
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
#define AID_SDCARD_RW 1015 /* external storage write access */
#define AID_VPN 1016 /* vpn system */
#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
#define AID_GPS 1021 /* GPS daemon */
#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
#define AID_MEDIA_RW 1023 /* internal media storage write access */
#define AID_MTP 1024 /* MTP USB driver access */
#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
#define AID_DRMRPC 1026 /* group for drm rpc */
#define AID_NFC 1027 /* nfc subsystem */
#define AID_SDCARD_R 1028 /* external storage read access */
#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_LOOP_RADIO 1030 /* loop radio devices */
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
#define AID_PACKAGE_INFO 1032 /* access to installed package details */
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
#define AID_DBUS 1038 /* dbus-daemon IPC broker process */
#define AID_TLSDATE 1039 /* tlsdate unprivileged user */
#define AID_MEDIA_EX 1040 /* mediaextractor process */
#define AID_AUDIOSERVER 1041 /* audioserver process */
#define AID_METRICS_COLL 1042 /* metrics_collector process */
#define AID_METRICSD 1043 /* metricsd process */
#define AID_WEBSERV 1044 /* webservd process */
#define AID_DEBUGGERD 1045 /* debuggerd unprivileged user */
#define AID_MEDIA_CODEC 1046 /* mediacodec process */
#define AID_CAMERASERVER 1047 /* cameraserver process */
#define AID_FIREWALL 1048 /* firewalld process */
#define AID_TRUNKS 1049 /* trunksd process (TPM daemon) */
#define AID_NVRAM 1050 /* Access-controlled NVRAM */
#define AID_DNS 1051 /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) */
#define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
#define AID_VEHICLE_NETWORK 1054 /* Vehicle network service */
#define AID_MEDIA_AUDIO 1055 /* GID for audio files on internal media storage */
#define AID_MEDIA_VIDEO 1056 /* GID for video files on internal media storage */
#define AID_MEDIA_IMAGE 1057 /* GID for image files on internal media storage */
#define AID_TOMBSTONED 1058 /* tombstoned user */
#define AID_MEDIA_OBB 1059 /* GID for OBB files on internal media storage */
#define AID_ESE 1060 /* embedded secure element (eSE) subsystem */
#define AID_OTA_UPDATE 1061 /* resource tracking UID for OTA updates */
#define AID_AUTOMOTIVE_EVS 1062 /* Automotive rear and surround view system */
#define AID_LOWPAN 1063 /* LoWPAN subsystem */
#define AID_HSM 1064 /* hardware security module subsystem */
#define AID_RESERVED_DISK 1065 /* GID that has access to reserved disk space */
#define AID_STATSD 1066 /* statsd daemon */
#define AID_INCIDENTD 1067 /* incidentd daemon */
#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
#define AID_LMKD 1069 /* low memory killer daemon */
#define AID_LLKD 1070 /* live lock daemon */
#define AID_IORAPD 1071 /* input/output readahead and pin daemon */
#define AID_GPU_SERVICE 1072 /* GPU service daemon */
#define AID_NETWORK_STACK 1073 /* network stack service */
#define AID_GSID 1074 /* GSI service daemon */
#define AID_FSVERITY_CERT 1075 /* fs-verity key ownership in keystore */
#define AID_CREDSTORE 1076 /* identity credential manager service */
#define AID_EXTERNAL_STORAGE 1077 /* Full external storage access including USB OTG volumes */
#define AID_EXT_DATA_RW 1078 /* GID for app-private data directories on external storage */
#define AID_EXT_OBB_RW 1079 /* GID for OBB directories on external storage */
#define AID_CONTEXT_HUB 1080 /* GID for access to the Context Hub */
#define AID_VIRTUALIZATIONSERVICE 1081 /* VirtualizationService daemon */
#define AID_ARTD 1082 /* ART Service daemon */
#define AID_UWB 1083 /* UWB subsystem */
#define AID_THREAD_NETWORK 1084 /* Thread Network subsystem */
#define AID_DICED 1085 /* Android's DICE daemon */
#define AID_DMESGD 1086 /* dmesg parsing daemon for kernel report collection */
#define AID_JC_WEAVER 1087 /* Javacard Weaver HAL - to manage omapi ARA rules */
#define AID_JC_STRONGBOX 1088 /* Javacard Strongbox HAL - to manage omapi ARA rules */
#define AID_JC_IDENTITYCRED 1089 /* Javacard Identity Cred HAL - to manage omapi ARA rules */
#define AID_SDK_SANDBOX 1090 /* SDK sandbox virtual UID */
#define AID_SECURITY_LOG_WRITER 1091 /* write to security log */
#define AID_PRNG_SEEDER 1092 /* PRNG seeder daemon */
#define AID_UPROBESTATS 1093 /* uid for uprobestats */
#define AID_CROS_EC 1094 /* uid for accessing ChromeOS EC (cros_ec) */
#define AID_MMD 1095 /* uid for memory management daemon */
#define AID_UPDATE_ENGINE_LOG 1096 /* GID for accessing update_engine logs */
// Additions to this file must be made in AOSP, *not* in internal branches.
// You will also need to update expect_ids() in bionic/tests/grp_pwd_test.cpp.
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources */
/* The range 2900-2999 is reserved for the vendor partition */
/* Note that the two 'OEM' ranges pre-dated the vendor partition, so they take the legacy 'OEM'
* name. Additionally, they pre-dated passwd/group files, so there are users and groups named oem_#
* created automatically for all values in these ranges. If there is a user/group in a passwd/group
* file corresponding to this range, both the oem_# and user/group names will resolve to the same
* value. */
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 2999
/* The 3000 series are intended for use as supplemental group ids only.
* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_READPROC 3009 /* Allow /proc read access */
#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */
#define AID_UHID 3011 /* Allow read/write to /dev/uhid node */
#define AID_READTRACEFS 3012 /* Allow tracefs read */
#define AID_VIRTUALMACHINE 3013 /* Allows VMs to tune for performance*/
// Additions to this file must be made in AOSP, *not* in internal branches.
// You will also need to update expect_ids() in bionic/tests/grp_pwd_test.cpp.
/* The range 5000-5999 is also reserved for vendor partition. */
#define AID_OEM_RESERVED_2_START 5000
#define AID_OEM_RESERVED_2_END 5999
/* The range 6000-6499 is reserved for the system partition. */
#define AID_SYSTEM_RESERVED_START 6000
#define AID_SYSTEM_RESERVED_END 6499
/* The range 6500-6999 is reserved for the odm partition. */
#define AID_ODM_RESERVED_START 6500
#define AID_ODM_RESERVED_END 6999
/* The range 7000-7499 is reserved for the product partition. */
#define AID_PRODUCT_RESERVED_START 7000
#define AID_PRODUCT_RESERVED_END 7499
/* The range 7500-7999 is reserved for the system_ext partition. */
#define AID_SYSTEM_EXT_RESERVED_START 7500
#define AID_SYSTEM_EXT_RESERVED_END 7999
#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
#define AID_APP 10000 /* TODO: switch users over to AID_APP_START */
#define AID_APP_START 10000 /* first app user */
#define AID_APP_END 19999 /* last app user */
#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */
#define AID_CACHE_GID_END 29999 /* end of gids for apps to mark cached data */
#define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */
#define AID_EXT_GID_END 39999 /* end of gids for apps to mark external data */
#define AID_EXT_CACHE_GID_START 40000 /* start of gids for apps to mark external cached data */
#define AID_EXT_CACHE_GID_END 49999 /* end of gids for apps to mark external cached data */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */
/*
* This is a magic number in the kernel and not something that was picked
* arbitrarily. This value is returned whenever a uid that has no mapping in the
* user namespace is returned to userspace:
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/highuid.h?h=v4.4#n40
*/
#define AID_OVERFLOWUID 65534 /* unmapped user in the user namespace */
/* use the ranges below to determine whether a process is sdk sandbox */
#define AID_SDK_SANDBOX_PROCESS_START 20000 /* start of uids allocated to sdk sandbox processes */
#define AID_SDK_SANDBOX_PROCESS_END 29999 /* end of uids allocated to sdk sandbox processes */
/* use the ranges below to determine whether a process is isolated */
#define AID_ISOLATED_START 90000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
#define AID_USER 100000 /* TODO: switch users over to AID_USER_OFFSET */
#define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */
/*
* android_ids has moved to pwd/grp functionality.
* If you need to add one, the structure is now
* auto-generated based on the AID_ constraints
* documented at the top of this header file.
* Also see build/tools/fs_config for more details.
*/

View File

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

View File

@@ -27,9 +27,7 @@
#include <libhelper/lib.hpp>
namespace Helper {
Error::Error(const char* format, ...)
{
Error::Error(const char *format, ...) {
char buf[1024];
va_list args;
va_start(args, format);
@@ -39,15 +37,16 @@ Error::Error(const char* format, ...)
LOGN(HELPER, ERROR) << _message << std::endl;
}
const char* Error::what() const noexcept
{
const char *Error::what() const noexcept {
return _message.data();
}
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(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;
char str[1024];
snprintf(str, sizeof(str), "<%c> [ <prog %s> <on %s:%d> %s %s] %s(): %s",
@@ -64,7 +63,8 @@ Logger::~Logger()
if (const int fd = open(_logFile, O_WRONLY | O_CREAT, DEFAULT_EXTENDED_FILE_PERMS); fd != -1) close(fd);
else {
LoggingProperties::setLogFile("last_logs.log");
LOGN(HELPER, INFO) << "Cannot create log file: " << _logFile << ": " << strerror(errno) << " New logging file: last_logs.log (this file)." << std::endl;
LOGN(HELPER, INFO) << "Cannot create log file: " << _logFile << ": " << strerror(errno) <<
" New logging file: last_logs.log (this file)." << std::endl;
}
}
@@ -73,16 +73,27 @@ Logger::~Logger()
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;
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", str);
}
Logger& Logger::operator<<(std::ostream& (*msg)(std::ostream&))
{
Logger &Logger::operator<<(std::ostream & (*msg)(std::ostream &)) {
_oss << msg;
return *this;
}
garbageCollector::~garbageCollector() {
for (const auto& ptr : _ptrs_c) delete[] ptr;
for (const auto& ptr : _ptrs_u) delete[] ptr;
for (const auto& fd : _fds) close(fd);
for (const auto& fp : _fps) fclose(fp);
}
void garbageCollector::delAfterProgress(char* &_ptr) { _ptrs_c.push_back(_ptr); }
void garbageCollector::delAfterProgress(uint8_t *&_ptr) { _ptrs_u.push_back(_ptr); }
void garbageCollector::closeAfterProgress(const int _fd) { _fds.push_back(_fd); }
void garbageCollector::delAfterProgress(FILE* &_fp) { _fps.push_back(_fp); }
} // namespace Helper

View File

@@ -25,78 +25,62 @@
#include <sys/stat.h>
#include <libhelper/lib.hpp>
static FILE* open_file(const std::string_view file, const char* mode)
{
FILE* fp = fopen(file.data(), mode);
if (fp == nullptr) return nullptr;
return fp;
}
namespace Helper {
bool writeFile(const std::string_view file, const std::string_view text)
{
bool writeFile(const std::string_view file, const std::string_view text) {
LOGN(HELPER, INFO) << "write \"" << text << "\" to " << file << "requested." << std::endl;
FILE* fp = open_file(file, "a");
garbageCollector collector;
FILE *fp = openAndAddToCloseList(file, collector, "a");
if (fp == nullptr) return false;
fprintf(fp, "%s", text.data());
fclose(fp);
LOGN(HELPER, INFO) << "write " << file << " successfull." << std::endl;
LOGN(HELPER, INFO) << "write " << file << " successfully." << std::endl;
return true;
}
std::optional<std::string> readFile(const std::string_view file)
{
std::optional<std::string> readFile(const std::string_view file) {
LOGN(HELPER, INFO) << "read " << file << " requested." << std::endl;
FILE* fp = open_file(file, "r");
garbageCollector collector;
FILE *fp = openAndAddToCloseList(file, collector, "r");
if (fp == nullptr) return std::nullopt;
char buffer[1024];
std::string str;
while (fgets(buffer, sizeof(buffer), fp)) str += buffer;
fclose(fp);
LOGN(HELPER, INFO) << "read " << file << " successfull, readed text: \"" << str << "\"" << std::endl;
LOGN(HELPER, INFO) << "read " << file << " successfully, read text: \"" << str << "\"" << std::endl;
return str;
}
bool copyFile(const std::string_view file, const std::string_view dest)
{
bool copyFile(const std::string_view file, const std::string_view dest) {
LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " requested." << std::endl;
garbageCollector collector;
const int src_fd = open(file.data(), O_RDONLY);
const int src_fd = openAndAddToCloseList(file.data(), collector, O_RDONLY);
if (src_fd == -1) return false;
const int dst_fd = open(dest.data(), O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_PERMS);
const int dst_fd = openAndAddToCloseList(dest.data(), collector, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_PERMS);
if (dst_fd == -1) return false;
char buffer[512];
ssize_t br;
while ((br = read(src_fd, buffer, 512)) > 0) {
if (const ssize_t bw = write(dst_fd, buffer, br); bw != br) return false;
}
close(src_fd);
close(dst_fd);
if (br == -1) return false;
LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " successfull." << std::endl;
LOGN(HELPER, INFO) << "copy " << file << " to " << dest << " successfully." << std::endl;
return true;
}
bool makeDirectory(const std::string_view path)
{
bool makeDirectory(const std::string_view path) {
if (isExists(path)) return false;
LOGN(HELPER, INFO) << "trying making directory: " << path << std::endl;
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;
char tmp[PATH_MAX];
@@ -124,8 +108,7 @@ bool makeRecursiveDirectory(const std::string_view paths)
return true;
}
bool createFile(const std::string_view path)
{
bool createFile(const std::string_view path) {
LOGN(HELPER, INFO) << "create file request: " << path << std::endl;
if (isExists(path)) return false;
@@ -138,8 +121,7 @@ bool createFile(const std::string_view path)
return true;
}
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;
if (const int ret = symlink(entry1.data(), entry2.data()); ret != 0) return false;
@@ -147,17 +129,15 @@ bool createSymlink(const std::string_view entry1, const std::string_view entry2)
return true;
}
bool eraseEntry(const std::string_view entry)
{
bool eraseEntry(const std::string_view entry) {
LOGN(HELPER, INFO) << "erase \"" << entry << "\" requested." << std::endl;
if (int ret = remove(entry.data()); ret != 0) return false;
if (const int ret = remove(entry.data()); ret != 0) return false;
LOGN(HELPER, INFO) << "\"" << entry << "\" erased successfully." << std::endl;
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;
struct stat buf{};
dirent *entry;
@@ -199,8 +179,7 @@ bool eraseDirectoryRecursive(const std::string_view directory)
return true;
}
std::string readSymlink(const std::string_view entry)
{
std::string readSymlink(const std::string_view entry) {
LOGN(HELPER, INFO) << "read symlink request: " << entry << std::endl;
char target[PATH_MAX];
@@ -212,12 +191,10 @@ std::string readSymlink(const std::string_view entry)
return target;
}
size_t fileSize(const std::string_view file)
{
size_t fileSize(const std::string_view file) {
LOGN(HELPER, INFO) << "get file size request: " << file << std::endl;
struct stat st{};
if (stat(file.data(), &st) != 0) return false;
return static_cast<size_t>(st.st_size);
}
} // namespace Helper

View File

@@ -24,10 +24,9 @@
#include <libhelper/lib.hpp>
namespace Helper {
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;
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;
std::string fp = (isLink(path)) ? readSymlink(path) : std::string(path);
if (!fileIsExists(fp)) throw Error("Is not exists or not file: %s", fp.data());
@@ -36,12 +35,11 @@ std::optional<std::string> sha256Of(const std::string_view path)
std::vector<unsigned char> hash(picosha2::k_digest_size);
picosha2::hash256(fp, hash.begin(), hash.end());
LOGN(HELPER, INFO) << "get sha256 of \"" << path << "\" successfull." << std::endl;
LOGN(HELPER, INFO) << "get sha256 of \"" << path << "\" successfully." << std::endl;
return picosha2::bytes_to_hex_string(hash.begin(), hash.end());
}
bool sha256Compare(const std::string_view file1, const std::string_view file2)
{
bool sha256Compare(const std::string_view file1, const std::string_view file2) {
LOGN(HELPER, INFO) << "comparing sha256 signatures of input files." << std::endl;
const auto f1 = sha256Of(file1);
const auto f2 = sha256Of(file2);
@@ -49,5 +47,4 @@ bool sha256Compare(const std::string_view file1, const std::string_view file2)
LOGN_IF(HELPER, INFO, *f1 == *f2) << "(): input files is contains same sha256 signature." << std::endl;
return (*f1 == *f2);
}
} // namespace Helper

View File

@@ -22,55 +22,79 @@
#include <cstdlib>
#include <unistd.h>
#include <ctime>
#include <fcntl.h>
#include <libgen.h>
#include <libhelper/lib.hpp>
#include <generated/buildInfo.hpp>
#include <sys/stat.h>
#include <sys/_system_properties.h>
#include <cutils/android_reboot.h>
// From system/core/libcutils/android_reboot.cpp android16-s2-release
int android_reboot(const unsigned cmd, int /*flags*/, const char* arg) {
int ret;
const char* restart_cmd = nullptr;
char* prop_value;
switch (cmd) {
case ANDROID_RB_RESTART: // deprecated
case ANDROID_RB_RESTART2:
restart_cmd = "reboot";
break;
case ANDROID_RB_POWEROFF:
restart_cmd = "shutdown";
break;
case ANDROID_RB_THERMOFF:
restart_cmd = "shutdown,thermal";
break;
}
if (!restart_cmd) return -1;
if (arg && arg[0]) ret = asprintf(&prop_value, "%s,%s", restart_cmd, arg);
else ret = asprintf(&prop_value, "%s", restart_cmd);
if (ret < 0) return -1;
ret = __system_property_set(ANDROID_RB_PROPERTY, prop_value);
free(prop_value);
return ret;
}
namespace Helper {
namespace LoggingProperties {
std::string_view FILE = "last_logs.log", NAME = "main";
bool PRINT = NO, DISABLE = NO;
void reset()
{
void reset() {
FILE = "last_logs.log";
NAME = "main";
PRINT = NO;
}
void set(std::string_view file, std::string_view name)
{
void set(std::string_view file, std::string_view name) {
if (file.data() != nullptr) FILE = file;
if (name.data() != nullptr) NAME = name;
}
void setProgramName(std::string_view name) { NAME = name; }
void setLogFile(std::string_view file) { FILE = file; }
void setProgramName(const std::string_view name) { NAME = name; }
void setLogFile(const std::string_view file) { FILE = file; }
void setPrinting(int state)
{
void setPrinting(const int state) {
if (state == 1 || state == 0) PRINT = state;
else PRINT = NO;
}
void setLoggingState(int state)
{
void setLoggingState(const int state) {
if (state == 1 || state == 0) DISABLE = state;
else DISABLE = NO;
}
} // namespace LoggingProperties
bool runCommand(const std::string_view cmd)
{
bool runCommand(const std::string_view cmd) {
LOGN(HELPER, INFO) << "run command request: " << cmd << std::endl;
return (system(cmd.data()) == 0) ? true : false;
}
bool confirmPropt(const std::string_view message)
{
bool confirmPropt(const std::string_view message) {
LOGN(HELPER, INFO) << "create confirm propt request. Creating." << std::endl;
char p;
@@ -84,15 +108,13 @@ bool confirmPropt(const std::string_view message)
return confirmPropt(message);
}
std::string currentWorkingDirectory()
{
std::string currentWorkingDirectory() {
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) == nullptr) return {};
return cwd;
}
std::string currentDate()
{
std::string currentDate() {
const time_t t = time(nullptr);
if (const tm *date = localtime(&t))
@@ -103,8 +125,7 @@ std::string currentDate()
return "--/--/----";
}
std::string currentTime()
{
std::string currentTime() {
const time_t t = time(nullptr);
if (const tm *date = localtime(&t))
@@ -115,8 +136,7 @@ std::string currentTime()
return "--:--:--";
}
std::string runCommandWithOutput(const std::string_view cmd)
{
std::string runCommandWithOutput(const std::string_view cmd) {
LOGN(HELPER, INFO) << "run command and catch out request: " << cmd << std::endl;
FILE *pipe = popen(cmd.data(), "r");
@@ -132,41 +152,63 @@ std::string runCommandWithOutput(const std::string_view cmd)
return output;
}
std::string pathJoin(std::string base, std::string relative)
{
std::string pathJoin(std::string base, std::string relative) {
if (base.back() != '/') base += '/';
if (relative[0] == '/') relative.erase(0, 1);
base += relative;
return base;
}
std::string pathBasename(const std::string_view entry)
{
std::string pathBasename(const std::string_view entry) {
char *base = basename(const_cast<char *>(entry.data()));
return (base == nullptr) ? std::string() : std::string(base);
}
std::string pathDirname(const std::string_view entry)
{
std::string pathDirname(const std::string_view entry) {
char *base = dirname(const_cast<char *>(entry.data()));
return (base == nullptr) ? std::string() : std::string(base);
}
bool changeMode(const std::string_view file, const mode_t mode)
{
bool changeMode(const std::string_view file, const mode_t mode) {
LOGN(HELPER, INFO) << "change mode request: " << file << ". As mode: " << mode << std::endl;
return chmod(file.data(), mode) == 0;
}
bool changeOwner(const std::string_view file, const uid_t uid, const gid_t gid)
{
bool changeOwner(const std::string_view file, const uid_t uid, 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()
{
MKVERSION("libhelper");
int openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, const int flags, const mode_t mode) {
const int fd = mode == 0 ? open(path.data(), flags) : open(path.data(), flags, mode);
collector.closeAfterProgress(fd);
return fd;
}
FILE* openAndAddToCloseList(const std::string_view& path, garbageCollector &collector, const char* mode) {
FILE *fp = fopen(path.data(), mode);
collector.delAfterProgress(fp);
return fp;
}
std::string getProperty(const std::string_view prop) {
char val[PROP_VALUE_MAX];
const int x = __system_property_get(prop.data(), val);
return x > 0 ? val : "ERROR";
}
bool reboot(const std::string_view arg) {
LOGN(HELPER, INFO) << "reboot request sent!!!" << std::endl;
unsigned cmd = ANDROID_RB_RESTART2;
if (const std::string prop = getProperty("ro.build.version.sdk"); prop != "ERROR") {
if (std::stoi(prop) < 26) cmd = ANDROID_RB_RESTART;
}
return android_reboot(cmd, 0, arg.empty() ? nullptr : arg.data()) != -1;
}
std::string getLibVersion() {
MKVERSION("libhelper");
}
} // namespace Helper

View File

@@ -17,6 +17,7 @@
# Sources
set(LIBPARTITION_MAP_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/Getters.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Magic.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/PartitionMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Type.cpp
)

View File

@@ -22,13 +22,13 @@
#include <optional>
#include <exception>
#include <list>
#include <unordered_map>
#include <memory>
#include <utility> // for std::pair
#include <cstdint> // for uint64_t
#include <libhelper/lib.hpp>
namespace PartitionMap {
struct _entry {
std::string name;
@@ -45,6 +45,7 @@ struct _entry {
class basic_partition_map final {
private:
void _resize_map();
[[nodiscard]] int _index_of(std::string_view name) const;
public:
@@ -65,6 +66,8 @@ public:
bool insert(const std::string &name, uint64_t size, bool logical);
void merge(const basic_partition_map &map);
void clear();
[[nodiscard]] uint64_t get_size(std::string_view name) const;
[[nodiscard]] bool is_logical(std::string_view name) const;
[[nodiscard]] _returnable_entry get_all(std::string_view name) const;
@@ -72,9 +75,9 @@ public:
[[nodiscard]] std::string find_(const std::string &name) const;
[[nodiscard]] size_t size() const;
[[nodiscard]] bool empty() const;
void clear();
basic_partition_map &operator=(const basic_partition_map &map);
bool operator==(const basic_partition_map &other) const;
bool operator!=(const basic_partition_map &other) const;
@@ -109,7 +112,6 @@ public:
/* for-each support */
[[nodiscard]] iterator begin() const;
[[nodiscard]] iterator end() const;
[[nodiscard]] constant_iterator cbegin() const;
[[nodiscard]] constant_iterator cend() const;
};
@@ -122,10 +124,12 @@ private:
std::string _workdir;
bool _any_generating_error, _map_builded;
[[nodiscard]] static bool _is_real_block_dir(std::string_view path);
Map_t _build_map(std::string_view path, bool logical = false);
void _insert_logicals(Map_t &&logicals);
void _map_build_check() const;
[[nodiscard]] static bool _is_real_block_dir(std::string_view path);
[[nodiscard]] uint64_t _get_size(const std::string &path);
public:
@@ -284,6 +288,39 @@ std::string getLibVersion();
using BuildMap = basic_partition_map_builder;
using Map = basic_partition_map_builder;
namespace Extras {
namespace FileSystemMagic {
constexpr uint64_t EXTFS_FS = 0xEF53;
constexpr uint64_t F2FS_FS = 0xF2F52010;
constexpr uint64_t EROFS_FS = 0xE0F5E1E2;
constexpr uint64_t EXFAT_FS = 0x5441465845;
constexpr uint64_t FAT12_FS = 0x3231544146;
constexpr uint64_t FAT16_FS = 0x3631544146;
constexpr uint64_t FAT32_FS = 0x3233544146;
constexpr uint64_t NTFS_FS = 0x5346544E;
constexpr uint64_t MSDOS_FS = 0x4d44;
} // namespace FileSystemMagic
namespace AndroidMagic {
constexpr uint64_t BOOT_IMAGE = 0x2144494F52444E41;
constexpr uint64_t VBOOT_IMAGE = 0x544F4F4252444E56;
constexpr uint64_t LK_IMAGE = 0x00006B6C;
constexpr uint64_t DTBO_IMAGE = 0x1EABB7D7;
constexpr uint64_t VBMETA_IMAGE = 0x425641;
constexpr uint64_t SUPER_IMAGE = 0x7265797573;
constexpr uint64_t SPARSE_IMAGE = 0x3AFF26ED;
constexpr uint64_t ELF = 0x464C457F; // It makes more sense than between file systems
constexpr uint64_t RAW = 0x00000000;
} // namespace AndroidMagic
extern std::unordered_map<uint64_t, std::string> FileSystemMagicMap;
extern std::unordered_map<uint64_t, std::string> AndroidMagicMap;
extern std::unordered_map<uint64_t, std::string> MagicMap;
size_t getMagicLength(uint64_t magic);
bool hasMagic(uint64_t magic, ssize_t buf, const std::string &path);
std::string formatMagic(uint64_t magic);
} // namespace Extras
} // namespace PartitionMap
#define MAP "libpartition_map"

View File

@@ -20,23 +20,19 @@
#include <libpartition_map/lib.hpp>
namespace PartitionMap {
Map_t basic_partition_map_builder::getAll() const
{
Map_t basic_partition_map_builder::getAll() const {
_map_build_check();
return _current_map;
}
std::optional<std::pair<uint64_t, bool>> basic_partition_map_builder::get(const std::string_view name) const
{
std::optional<std::pair<uint64_t, bool> > basic_partition_map_builder::get(const std::string_view name) const {
_map_build_check();
if (!_current_map.find(name)) return std::nullopt;
return std::make_pair(_current_map.get_size(name), _current_map.is_logical(name));
}
std::optional<std::list<std::string>> basic_partition_map_builder::getLogicalPartitionList() const
{
std::optional<std::list<std::string> > basic_partition_map_builder::getLogicalPartitionList() const {
_map_build_check();
std::list<std::string> logicals;
@@ -47,8 +43,7 @@ std::optional<std::list<std::string>> basic_partition_map_builder::getLogicalPar
return logicals;
}
std::optional<std::list<std::string>> basic_partition_map_builder::getPhysicalPartitionList() const
{
std::optional<std::list<std::string> > basic_partition_map_builder::getPhysicalPartitionList() const {
_map_build_check();
std::list<std::string> physicals;
@@ -69,19 +64,19 @@ std::optional<std::list<std::string>> basic_partition_map_builder::getPartitionL
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();
if (!_current_map.find(name)) return {};
return std::string(_workdir + "/" + name.data());
}
std::string basic_partition_map_builder::getRealPathOf(const std::string_view name) const
{
std::string basic_partition_map_builder::getRealPathOf(const std::string_view name) const {
_map_build_check();
const std::string full = (isLogical(name)) ? std::string("/dev/block/mapper/") + name.data() : _workdir + "/" + name.data();
const std::string full = (isLogical(name))
? std::string("/dev/block/mapper/") + name.data()
: _workdir + "/" + name.data();
if (!_current_map.find(name)
|| !std::filesystem::is_symlink(full))
return {};
@@ -89,9 +84,7 @@ std::string basic_partition_map_builder::getRealPathOf(const std::string_view na
return std::filesystem::read_symlink(full);
}
std::string basic_partition_map_builder::getCurrentWorkDir() const
{
std::string basic_partition_map_builder::getCurrentWorkDir() const {
return _workdir;
}
} // namespace PartitionMap

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 <fcntl.h>
#include <unistd.h>
#include <sstream>
#include <string>
#include <unordered_map>
#include <libhelper/lib.hpp>
#include <libpartition_map/lib.hpp>
#include "PartitionManager/PartitionManager.hpp"
namespace PartitionMap::Extras {
std::unordered_map<uint64_t, std::string> FileSystemMagicMap = {
{FileSystemMagic::EXTFS_FS, "EXT2/3/4"},
{FileSystemMagic::F2FS_FS, "F2FS"},
{FileSystemMagic::EROFS_FS, "EROFS"},
{FileSystemMagic::EXFAT_FS, "exFAT"},
{FileSystemMagic::FAT12_FS, "FAT12"},
{FileSystemMagic::FAT16_FS, "FAT16"},
{FileSystemMagic::FAT32_FS, "FAT32"},
{FileSystemMagic::NTFS_FS, "NTFS"},
{FileSystemMagic::MSDOS_FS, "MSDOS"}
};
std::unordered_map<uint64_t, std::string> AndroidMagicMap = {
{AndroidMagic::BOOT_IMAGE, "Android Boot Image"},
{AndroidMagic::VBOOT_IMAGE, "Android Vendor Boot Image"},
{AndroidMagic::LK_IMAGE, "Android LK (Bootloader)"},
{AndroidMagic::DTBO_IMAGE, "Android DTBO Image"},
{AndroidMagic::VBMETA_IMAGE, "Android VBMeta Image"},
{AndroidMagic::SUPER_IMAGE, "Android Super Image"},
{AndroidMagic::SPARSE_IMAGE, "Android Sparse Image"},
{AndroidMagic::ELF, "ELF"},
{AndroidMagic::RAW, "Raw Data"}
};
std::unordered_map<uint64_t, std::string> MagicMap = {
{AndroidMagic::BOOT_IMAGE, "Android Boot Image"},
{AndroidMagic::VBOOT_IMAGE, "Android Vendor Boot Image"},
{AndroidMagic::LK_IMAGE, "Android LK (Bootloader)"},
{AndroidMagic::DTBO_IMAGE, "Android DTBO Image"},
{AndroidMagic::VBMETA_IMAGE, "Android VBMeta Image"},
{AndroidMagic::SUPER_IMAGE, "Android Super Image"},
{AndroidMagic::SPARSE_IMAGE, "Android Sparse Image"},
{AndroidMagic::ELF, "ELF"},
{AndroidMagic::RAW, "Raw Data"},
{FileSystemMagic::EXTFS_FS, "EXT2/3/4"},
{FileSystemMagic::F2FS_FS, "F2FS"},
{FileSystemMagic::EROFS_FS, "EROFS"},
{FileSystemMagic::EXFAT_FS, "exFAT"},
{FileSystemMagic::FAT12_FS, "FAT12"},
{FileSystemMagic::FAT16_FS, "FAT16"},
{FileSystemMagic::FAT32_FS, "FAT32"},
{FileSystemMagic::NTFS_FS, "NTFS"},
{FileSystemMagic::MSDOS_FS, "MSDOS"}
};
size_t getMagicLength(const uint64_t magic) {
size_t length = 0;
for (int i = 0; i < 8; i++) {
if ((magic >> (8 * i)) & 0xFF) length = i + 1;
}
return length;
}
bool hasMagic(const uint64_t magic, const ssize_t buf, const std::string &path) {
LOGN(MAP, INFO) << "Checking magic of " << path << " with using " << buf << " byte buffer size (has magic 0x" << std::hex << magic << "?)" << std::endl;
Helper::garbageCollector collector;
const int fd = Helper::openAndAddToCloseList(path, collector, O_RDONLY);
if (fd < 0) return false;
if (buf < 1) {
LOGN(MAP, ERROR) << "Buffer size is older than 1" << std::endl;
return false;
}
auto *buffer = new uint8_t[buf];
collector.delAfterProgress(buffer);
const ssize_t bytesRead = read(fd, buffer, buf);
if (bytesRead < 0) return false;
const size_t magicLength = getMagicLength(magic);
if (magicLength == 0) return false;
for (size_t i = 0; i <= bytesRead - magicLength; i++) {
uint64_t value = 0;
for (size_t j = 0; j < magicLength; ++j) value |= static_cast<uint64_t>(buffer[i + j]) << (8 * j);
if (value == magic) {
LOGN(MAP, INFO) << path << " contains 0x" << std::hex << magic << std::endl;
return true;
}
}
LOGN(MAP, INFO) << path << " is not contains 0x" << std::hex << magic << std::endl;
return false;
}
std::string formatMagic(const uint64_t magic) {
std::stringstream ss;
ss << "0x" << std::uppercase << std::hex << std::setw(16) << std::setfill('0') << magic;
return ss.str();
}
} // namespace PartitionMap::Extras

View File

@@ -39,9 +39,7 @@ static constexpr std::array<std::string_view, 3> defaultEntryList = {
};
namespace PartitionMap {
bool basic_partition_map_builder::_is_real_block_dir(const std::string_view path)
{
bool basic_partition_map_builder::_is_real_block_dir(const std::string_view path) {
if (path.find("/block/") == std::string::npos) {
LOGN(MAP, ERROR) << "Path " << path << " is not a real block directory.";
return false;
@@ -49,15 +47,17 @@ bool basic_partition_map_builder::_is_real_block_dir(const std::string_view path
return true;
}
Map_t basic_partition_map_builder::_build_map(std::string_view path, bool logical)
{
Map_t basic_partition_map_builder::_build_map(std::string_view path, bool logical) {
Map_t map;
std::vector<std::filesystem::directory_entry> entries{std::filesystem::directory_iterator(path), std::filesystem::directory_iterator()};
std::vector<std::filesystem::directory_entry> entries{
std::filesystem::directory_iterator(path), std::filesystem::directory_iterator()
};
std::sort(entries.begin(), entries.end(), [](const auto &a, const auto &b) {
return a.path().filename() < b.path().filename();
});
LOGN_IF(MAP, WARNING, entries.empty()) << "" << path << "is exists but generated vector is empty (std::vector<std::filesystem::directory_entry>)." << std::endl;
LOGN_IF(MAP, WARNING, entries.empty()) << "" << path <<
"is exists but generated vector is empty (std::vector<std::filesystem::directory_entry>)." << std::endl;
for (const auto &entry: entries) {
if (entry.path().filename() != "by-uuid"
&& std::string(entry.path()).find("com.") == std::string::npos)
@@ -68,22 +68,21 @@ Map_t basic_partition_map_builder::_build_map(std::string_view path, bool logica
return map;
}
void basic_partition_map_builder::_insert_logicals(Map_t&& logicals)
{
void basic_partition_map_builder::_insert_logicals(Map_t &&logicals) {
LOGN(MAP, INFO) << "merging created logical partition list to this object's variable." << std::endl;
_current_map.merge(logicals);
}
void basic_partition_map_builder::_map_build_check() const
{
void basic_partition_map_builder::_map_build_check() const {
if (!_map_builded)
throw Error("Please build partition map before!");
}
uint64_t basic_partition_map_builder::_get_size(const std::string& path)
{
uint64_t basic_partition_map_builder::_get_size(const std::string &path) {
const std::string real = std::filesystem::read_symlink(path);
const int fd = open(real.data(), O_RDONLY);
Helper::garbageCollector collector;
const int fd = Helper::openAndAddToCloseList(real, collector, O_RDONLY);
if (fd < 0) {
LOGN(MAP, ERROR) << "Cannot open " << real << ": " << strerror(errno) << std::endl;
return 0;
@@ -91,17 +90,14 @@ uint64_t basic_partition_map_builder::_get_size(const std::string& path)
uint64_t size = 0;
if (ioctl(fd, BLKGETSIZE64, &size) != 0) {
close(fd);
LOGN(MAP, ERROR) << "ioctl() process failed for " << real << ": " << strerror(errno) << std::endl;
return 0;
}
close(fd);
return size;
}
basic_partition_map_builder::basic_partition_map_builder()
{
basic_partition_map_builder::basic_partition_map_builder() {
LOGN(MAP, INFO) << "default constructor called. Starting build." << std::endl;
for (const auto &path: defaultEntryList) {
@@ -124,8 +120,7 @@ basic_partition_map_builder::basic_partition_map_builder()
_map_builded = true;
}
basic_partition_map_builder::basic_partition_map_builder(const std::string_view path)
{
basic_partition_map_builder::basic_partition_map_builder(const std::string_view path) {
LOGN(MAP, INFO) << "argument-based constructor called. Starting build." << std::endl;
if (std::filesystem::exists(path)) {
@@ -141,27 +136,23 @@ basic_partition_map_builder::basic_partition_map_builder(const std::string_view
_map_builded = true;
}
bool basic_partition_map_builder::hasPartition(const std::string_view name) const
{
bool basic_partition_map_builder::hasPartition(const std::string_view name) const {
_map_build_check();
return _current_map.find(name);
}
bool basic_partition_map_builder::isLogical(const std::string_view name) const
{
bool basic_partition_map_builder::isLogical(const std::string_view name) const {
_map_build_check();
return _current_map.is_logical(name);
}
void basic_partition_map_builder::clear()
{
void basic_partition_map_builder::clear() {
_current_map.clear();
_workdir.clear();
_any_generating_error = false;
}
bool basic_partition_map_builder::readDirectory(const std::string_view path)
{
bool basic_partition_map_builder::readDirectory(const std::string_view path) {
_map_builded = false;
LOGN(MAP, INFO) << "read " << path << " directory request." << std::endl;
@@ -181,8 +172,7 @@ bool basic_partition_map_builder::readDirectory(const std::string_view path)
return true;
}
bool basic_partition_map_builder::readDefaultDirectories()
{
bool basic_partition_map_builder::readDefaultDirectories() {
_map_builded = false;
LOGN(MAP, INFO) << "read default directories request." << std::endl;
@@ -208,47 +198,38 @@ bool basic_partition_map_builder::readDefaultDirectories()
return true;
}
bool basic_partition_map_builder::empty() const
{
bool basic_partition_map_builder::empty() const {
_map_build_check();
return _current_map.empty();
}
uint64_t basic_partition_map_builder::sizeOf(const std::string_view name) const
{
uint64_t basic_partition_map_builder::sizeOf(const std::string_view name) const {
_map_build_check();
return _current_map.get_size(name);
}
bool operator==(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs)
{
bool operator==(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs) {
return lhs._current_map == rhs._current_map;
}
bool operator!=(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs)
{
bool operator!=(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs) {
return !(lhs == rhs);
}
basic_partition_map_builder::operator bool() const
{
basic_partition_map_builder::operator bool() const {
return !this->_any_generating_error;
}
bool basic_partition_map_builder::operator!() const
{
bool basic_partition_map_builder::operator!() const {
return this->_any_generating_error;
}
bool basic_partition_map_builder::operator()(const std::string_view path)
{
bool basic_partition_map_builder::operator()(const std::string_view path) {
LOGN(MAP, INFO) << "calling readDirectory() for building map with " << path << std::endl;
return readDirectory(path);
}
std::string getLibVersion()
{
std::string getLibVersion() {
MKVERSION("libpartition_map");
}
} // namespace PartitionMap

View File

@@ -20,79 +20,69 @@
#include <libpartition_map/lib.hpp>
namespace PartitionMap {
basic_partition_map::iterator::iterator(_entry *p) : ptr(p) {
}
basic_partition_map::iterator::iterator(_entry* p) : ptr(p) {}
auto basic_partition_map::iterator::operator*() const -> std::pair<std::string&, decltype(_entry::props)&>
{
auto basic_partition_map::iterator::operator*() const -> std::pair<std::string &, decltype(_entry::props) &> {
return {ptr->name, ptr->props};
}
_entry* basic_partition_map::iterator::operator->() const
{
_entry *basic_partition_map::iterator::operator->() const {
return ptr;
}
basic_partition_map::iterator& basic_partition_map::iterator::operator++()
{
basic_partition_map::iterator &basic_partition_map::iterator::operator++() {
++ptr;
return *this;
}
basic_partition_map::iterator basic_partition_map::iterator::operator++(int)
{
basic_partition_map::iterator basic_partition_map::iterator::operator++(int) {
iterator tmp = *this;
++ptr;
return tmp;
}
bool basic_partition_map::iterator::operator==(const iterator& other) const
{
bool basic_partition_map::iterator::operator==(const iterator &other) const {
return ptr == other.ptr;
}
bool basic_partition_map::iterator::operator!=(const iterator& other) const
{
bool basic_partition_map::iterator::operator!=(const iterator &other) const {
return ptr != other.ptr;
}
basic_partition_map::constant_iterator::constant_iterator(const _entry* p) : ptr(p) {}
basic_partition_map::constant_iterator::constant_iterator(const _entry *p) : ptr(p) {
}
auto basic_partition_map::constant_iterator::operator*() const -> std::pair<const std::string&, const decltype(_entry::props)&> {
auto basic_partition_map::constant_iterator::operator
*() const -> std::pair<const std::string &, const decltype(_entry::props) &> {
return {ptr->name, ptr->props};
}
const _entry* basic_partition_map::constant_iterator::operator->() const
{
const _entry *basic_partition_map::constant_iterator::operator->() const {
return ptr;
}
basic_partition_map::constant_iterator& basic_partition_map::constant_iterator::operator++()
{
basic_partition_map::constant_iterator &basic_partition_map::constant_iterator::operator++() {
++ptr;
return *this;
}
basic_partition_map::constant_iterator basic_partition_map::constant_iterator::operator++(int)
{
basic_partition_map::constant_iterator basic_partition_map::constant_iterator::operator++(int) {
constant_iterator tmp = *this;
++ptr;
return tmp;
}
bool basic_partition_map::constant_iterator::operator==(const constant_iterator& other) const
{
bool basic_partition_map::constant_iterator::operator==(const constant_iterator &other) const {
return ptr == other.ptr;
}
bool basic_partition_map::constant_iterator::operator!=(const constant_iterator& other) const
{
bool basic_partition_map::constant_iterator::operator!=(const constant_iterator &other) const {
return ptr != other.ptr;
}
void basic_partition_map::_resize_map()
{
void basic_partition_map::_resize_map() {
const size_t new_capacity = _capacity * 2;
auto *new_data = new _entry[new_capacity];
@@ -103,8 +93,7 @@ void basic_partition_map::_resize_map()
_capacity = new_capacity;
}
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++) {
if (name == _data[i].name) return static_cast<int>(i);
}
@@ -112,97 +101,83 @@ int basic_partition_map::_index_of(const std::string_view name) const
return 0;
}
basic_partition_map::basic_partition_map(const std::string& name, const uint64_t size, const bool logical)
{
basic_partition_map::basic_partition_map(const std::string &name, const uint64_t size, const bool logical) {
_data = new _entry[_capacity];
insert(name, size, logical);
}
basic_partition_map::basic_partition_map(const basic_partition_map& other) :
_data(new _entry[other._capacity]),
basic_partition_map::basic_partition_map(const basic_partition_map &other) : _data(new _entry[other._capacity]),
_count(other._count),
_capacity(other._capacity)
{
_capacity(other._capacity) {
std::copy(other._data, other._data + _count, _data);
}
basic_partition_map::basic_partition_map() : _capacity(6)
{
basic_partition_map::basic_partition_map() : _capacity(6) {
_data = new _entry[_capacity];
}
basic_partition_map::~basic_partition_map()
{
basic_partition_map::~basic_partition_map() {
delete[] _data;
}
bool basic_partition_map::insert(const std::string& name, const uint64_t size, const 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 (_count == _capacity) _resize_map();
_data[_count++] = {name, {size, logical}};
LOGN(MAP, INFO) << std::boolalpha << "partition " << name << " inserted (size=" << size << ", is_logical=" << logical << ")." << std::endl;
LOGN(MAP, INFO) << std::boolalpha << "partition " << name << " inserted (size=" << size << ", is_logical=" <<
logical << ")." << std::endl;
return true;
}
void basic_partition_map::merge(const basic_partition_map& map)
{
void basic_partition_map::merge(const basic_partition_map &map) {
LOGN(MAP, INFO) << "map merge request." << std::endl;
for (const auto &[name, props]: map)
insert(name, props.size, props.isLogical);
LOGN(MAP, INFO) << "map merged successfully." << std::endl;
}
uint64_t basic_partition_map::get_size(const std::string_view name) const
{
uint64_t basic_partition_map::get_size(const std::string_view name) const {
if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.size;
return 0;
}
bool basic_partition_map::is_logical(const std::string_view name) const
{
bool basic_partition_map::is_logical(const std::string_view name) const {
if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.isLogical;
return false;
}
basic_partition_map::_returnable_entry basic_partition_map::get_all(const std::string_view name) const
{
basic_partition_map::_returnable_entry basic_partition_map::get_all(const std::string_view name) const {
if (const int pos = _index_of(name); name == _data[pos].name)
return _returnable_entry{_data[pos].props.size, _data[pos].props.isLogical};
return _returnable_entry{};
}
bool basic_partition_map::find(const std::string_view name) const
{
bool basic_partition_map::find(const std::string_view name) const {
if (name == _data[_index_of(name)].name) return true;
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;
return {};
}
size_t basic_partition_map::size() const
{
size_t basic_partition_map::size() const {
return _count;
}
bool basic_partition_map::empty() const
{
bool basic_partition_map::empty() const {
if (_count > 0) return false;
return true;
}
void basic_partition_map::clear()
{
void basic_partition_map::clear() {
LOGN(MAP, INFO) << "map clean requested. Map is empty now." << std::endl;
delete[] _data;
_count = 0;
@@ -210,8 +185,7 @@ void basic_partition_map::clear()
_data = new _entry[_capacity];
}
basic_partition_map& basic_partition_map::operator=(const basic_partition_map& map)
{
basic_partition_map &basic_partition_map::operator=(const basic_partition_map &map) {
if (this != &map) {
delete[] _data;
@@ -224,8 +198,7 @@ basic_partition_map& basic_partition_map::operator=(const basic_partition_map& m
return *this;
}
bool basic_partition_map::operator==(const basic_partition_map& other) const
{
bool basic_partition_map::operator==(const basic_partition_map &other) const {
if (this->_capacity != other._capacity
|| this->_count != other._count)
return false;
@@ -241,29 +214,23 @@ bool basic_partition_map::operator==(const basic_partition_map& other) const
return true;
}
bool basic_partition_map::operator!=(const basic_partition_map& other) const
{
bool basic_partition_map::operator!=(const basic_partition_map &other) const {
return !(*this == other);
}
basic_partition_map::iterator basic_partition_map::begin() const
{
basic_partition_map::iterator basic_partition_map::begin() const {
return iterator(_data);
}
basic_partition_map::iterator basic_partition_map::end() const
{
basic_partition_map::iterator basic_partition_map::end() const {
return iterator(_data + _count);
}
basic_partition_map::constant_iterator basic_partition_map::cbegin() const
{
basic_partition_map::constant_iterator basic_partition_map::cbegin() const {
return constant_iterator(_data);
}
basic_partition_map::constant_iterator basic_partition_map::cend() const
{
basic_partition_map::constant_iterator basic_partition_map::cend() const {
return constant_iterator(_data + _count);
}
} // namespace PartitionMap