26
Library Documentation
Yağız Zengin edited this page 2025-09-30 21:11:30 +03:00

libhelper library

It provides functions, classes and macros that will make your work easier when writing your string program, such as the name libhelper.

Namespaces

Helper

Main namespace of the library.

#include <libhelper/lib.hpp>

Helpful macros and variables

libhelper provides some macros and variables to make your work easier.

// File/directory modes
constexpr mode_t DEFAULT_FILE_PERMS = 0644;
constexpr mode_t DEFAULT_EXTENDED_FILE_PERMS = 0755;
constexpr mode_t DEFAULT_DIR_PERMS = 0755;

// Boolean alternatives (is there anyone who will actually use it???)
constexpr int YES = 1; // YES = true
constexpr int NO = 0; // NO = false

// Macros that can be useful for size conversions
#define KB(x) (x * 1024)     // KB(8) = 8192 (8 * 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)

// Conversion from bytes to other units
#define TO_KB(x) (x / 1024)        // TO_KB(1024) = 1
#define TO_MB(x) (TO_KB(x) / 1024) // TO_MB(2048) (2048 / 1024)
#define TO_GB(x) (TO_MB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024)

// Macros to use for text decoration
#define STYLE_RESET "\033[0m"
#define BOLD "\033[1m"
#define FAINT "\033[2m"
#define ITALIC "\033[3m"
#define UNDERLINE "\033[4m"
#define BLINC "\033[5m"
#define FAST_BLINC "\033[6m"
#define STRIKE_THROUGHT "\033[9m"
#define NO_UNDERLINE "\033[24m"
#define NO_BLINC "\033[25m"
#define RED "\033[31m"
#define GREEN "\033[32m"
#define YELLOW "\033[33m"

// If NO_C_TYPE_HANDLERS is defined, these macros are can't defined.
#ifndef NO_C_TYPE_HANDLERS
// ABORT(message), ex: ABORT("memory error!\n")
#define ABORT(msg)                                                             \
  do {                                                                         \
    fprintf(stderr, "%s%sCRITICAL ERROR%s: %s\nAborting...\n", BOLD, RED,      \
            STYLE_RESET, msg);                                                 \
    abort();                                                                   \
  } while (0)

// ERROR(message, exit), ex: ERROR("an error occured.\n", 1)
#define ERROR(msg, code)                                                       \
  do {                                                                         \
    fprintf(stderr, "%s%sERROR%s: %s", BOLD, RED, STYLE_RESET, msg);           \
    exit(code);                                                                \
  } while (0)

// WARNING(message), ex: WARNING("using default setting.\n")
#define WARNING(msg)                                                           \
  fprintf(stderr, "%s%sWARNING%s: %s", BOLD, YELLOW, STYLE_RESET, msg);

// INFO(message), ex: INFO("operation ended.\n")
#define INFO(msg)                                                              \
  fprintf(stdout, "%s%sINFO%s: %s", BOLD, GREEN, STYLE_RESET, msg);
#endif // #ifndef NO_C_TYPE_HANDLERS

// Common version string creator.
// Don't forget to define the BUILD*** macros.
#define MKVERSION(name)                                                        \
  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)

Classes

libhelper provides three classes in total. One is for logging (used with macros), one is an error class created with std::exception, and the third is a garbage collector.


Logging Class

A total of four logging levels are provided: information, warning, error, and abort (critical error).

enum LogLevels {
  INFO = static_cast<int>('I'),
  WARNING = static_cast<int>('W'),
  ERROR = static_cast<int>('E'),
  ABORT = static_cast<int>('A')
};

// It actually seemed more logical to use the numerical equivalents of logical letters instead of numbers like 1-2.

A class called Logging handles everything. However, logging directly using the class isn't practical. There are some macros for this:

#define LOG(level)                                                             \
  Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(),      \
                 Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGF(file, level)                                                      \
  Helper::Logger(level, __func__, file,                                        \
                 Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGN(name, level)                                                      \
  Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(),      \
                 name, __FILE__, __LINE__)
#define LOGNF(name, file, level)                                               \
  Helper::Logger(level, file, name, __FILE__, __LINE__)

#define LOG_IF(level, condition)                                               \
  if (condition)                                                               \
  Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(),      \
                 Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGF_IF(file, level, condition)                                        \
  if (condition)                                                               \
  Helper::Logger(level, __func__, file,                                        \
                 Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGN_IF(name, level, condition)                                        \
  if (condition)                                                               \
  Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(),      \
                 name, __FILE__, __LINE__)
#define LOGNF_IF(name, file, level, condition)                                 \
  if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__)

There are some settings available for logging. These are stored in the Helper::LoggingProperties namespace. These are: FILE (std::string_view), NAME (std::string_view), PRINT (bool), DISABLE (bool). The default values are:

// Utilities.cpp

namespace Helper {
namespace LoggingProperties {
std::string_view FILE = "last_logs.log", NAME = "main";
bool PRINT = NO, DISABLE = NO;
} // namespace LoggingProperties
} // namespace Helper
  • PRINT specifies whether the log will be printed to the screen. This can be useful for things like verbose logging. The default is NO (false).
  • You can control logging with DISABLE. The default is NO (false). Setting it to true stops logging. No writing to the file.
  • FILE is the file where the log content will be saved. By default, it's last_logs.log. It's created in your current directory.
  • NAME is the name of the program that prints the log that will appear in the log. By default, it is main.

You can change these settings directly or use the provided functions.

namespace Helper {
namespace LoggingProperties {
void set(std::string_view name, std::string_view file);
void setProgramName(std::string_view name);
void setLogFile(std::string_view file);
template <int state>
void setPrinting();
template <int state>
void setLoggingState(); // Disable/enable logging

void reset();
} // namespace LoggingProperties
} // namespae Helper

It's pretty clear what the functions named set*** do. But I'd still like to mention reset(). It restores default settings. Now we can reinforce it with use cases. That would be good.

#include <libhelper/lib.hpp>
#include <iostream>
#include <string.h>

int main(int argc, char** argv) {
  Helper::LoggingProperties::set("pmt", "/storage/emulated/0/Dccuments/last_pmt_logs.log");

  LOG(INFO) << "Hello World!" << std::endl;
  LOGF("last_logs_test.log", INFO) << "Hello World!" << std::endl;
  LOG_IF(WARNING, argc < 2) << "No argument speficed!" << std::endl;
  LOGF_IF("last_logs_test.log", strcmp(argv[0], "pmt") == 0) << "This is pmt!" << std::endl;
  LOGN(argv[0], INFO) << "Hello World from " << argv[0] << " program!" << std::endl;
  LOGNF(argv[0], "last_logs_test.log", INFO) << "LOGNF() test!!!" << std::endl;
  LOGN_IF(argv[0], WARNING, argc < 2) << "No argument speficed! (test 2)" << std::endl;
  LOGNF_IF(argv[0], "last_logs_test.log", ERROR, argc > 3) << "Too many argument!" << std::endl;
  
  std::cout << "Program complete!" << std::endl;
  return 0;
}

Error Class

It is a throwable error class derived from std::exception. Thrown errors are also recorded in the logs. Can take printf() style input.

#include <libhelper/lib.hpp>
#include <iostream>

int main(int argc, char** argv) {
  try {
    if (argc < 2)
      throw Helper::Error("No enoght argument!");
  } catch (Helper::Error &e) {
    std::cerr << e.what() << std::endl;
    return 1;
  }
  
  return 0;
}

Garbage Collector Class

The garbage collector is there to free allocated memory (certain types) and close file pointers. In other words, it handles your work for you. It also has additional auxiliary functions.

namespace Helper {
class garbageCollector {
// Other definations...

public:
  ~garbageCollector();

  template <typename T>
  void delAfterProgress(T *_ptr); // Delete allocated variables after function
  void delFileAfterProgress(const std::string &_path); // Delete input file after function
  void closeAfterProgress(FILE *&_fp); // Close input file pointers after function
  void closeAfterProgress(DIR *&_dp); // Close input directory pointers after function
  void closeAfterProgress(int _fd); // Close input file descriptor after function
  
  // You can add whatever you want by using it multiple times
};

// Open input path with flags and add to integrity list. And return file descriptor. open() is emulated
[[nodiscard]] int openAndAddToCloseList(const std::string_view &path,
                                        garbageCollector &collector, int flags,
                                        mode_t mode = 0000);
// fopen() is emulated.
[[nodiscard]] FILE *openAndAddToCloseList(const std::string_view &path,
                                          garbageCollector &collector,
                                          const char *mode);
[[nodiscard]] DIR *openAndAddToCloseList(const std::string_view &path,
                                          garbageCollector &collector);

// You can need use returned values!!! Because these functions marked as nodiscard
} // namespace Helper

Usage example...

#include <libhelper/lib.hpp>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>

int main(int argc, char** argv) {
  Helper::garbageCollector collector;
  
  int fd1 = open("file.txt", O_TRUNC | O_CREAT, 0644);
  collector.closeAfterProgress(fd1); // no need close() anymore
  // You can do the same with FILE or DIR
  // Do your file progresses...
  
  // Delete file.txt automaticly after program
  collector.delFileAfterProgess("file.txt");
  
  int fd2 = Helper::openAndAddToCloseList("file2.txt", collector, O_TRUNC, DEFAULT_FILE_PERMS);
  // Do your file progresses...
  // WARNING: It does not check whether the file is opened or not.
  
  DIR *dp = Helper::openAndAddToCloseList("dir1", collector);
  // Do your directory progresses...
  // WARNING: It does not check whether the directory is opened or not.
  
  auto *buffer = new char[4096]; // Allocate memory
  collector.delAfterProgrss(buffer);
  // You can do the same with other types (int, etc.)
  
  return 0;
}

Functions

libhelper provides many helper functions. Some of these throw Helper::Error. We'll cover each one with code examples.

Checkers

  • bool hasSuperUser() - It is checked whether the user ID used is equivalent to AID_ROOT. See include/private/android_filesystem_config.h
  • bool hasAdbPermissions() - It is checked whether the user ID used is equivalent to AID_SHELL. See include/private/android_filesystem_config.h
  • bool isExists(std::string_view entry) - Checks whether the file/directory exists.
  • bool fileIsExists(std::string_view file) - Checks whether the file exists.
  • bool directoryIsExists(std::string_view directory) - Checks whether the directory exists.
  • bool linkIsExists(std::string_view entry) - Checks whether the link (symbolic or hard) exists.
  • bool isLink(std::string_view entry) - Checks if the entry is a symbolic link.
  • bool isSymbolicLink(std::string_view entry) - Checks if the entry is a symbolic link.
  • bool isHardLink(std::string_view entry) - Checks if the entry is a hard link.
  • bool areLinked(std::string_view entry1, std::string_view entry2) - Checks whether entry1 is linked to entry2.

File I/O

  • bool writeFile(std::string_view file, std::string_view text) - Writes given text into file. If file does not exist, it is automatically created. Returns true on success.
  • std::optional<std::string> readFile(std::string_view file) - Reads file content into string. On success returns file content. On error returns std::nullopt.

Creators

  • bool makeDirectory(std::string_view path) - Create directory.
  • bool makeRecursiveDirectory(std::string_view paths) - Create recursive directory.
  • bool createFile(std::string_view path) - Create file.
  • bool createSymlink(std::string_view entry1, std::string_view entry2) - Symlink entry1 to entry2.

Removers

  • bool eraseEntry(std::string_view entry) - Remove file or empty directory.
  • bool eraseDirectoryRecursive(std::string_view directory) - Remove directory and all directory contents recursively.

Getters

  • int64_t fileSize(std::string_view file) - Get file size.
  • std::string readSymlink(std::string_view entry) - Read symlinks.

SHA-256

  • bool sha256Compare(std::string_view file1, std::string_view file2) - Compare SHA-256 values of files. Throws Helper::Error on error occurred.
  • std::optional<std::string> sha256Of(std::string_view path) - Get SHA-256 of file. Throws Helper::Error on error occurred.

Utilities

  • bool copyFile(std::string_view file, std::string_view dest) - Copy file to dest.
  • bool runCommand(std::string_view cmd) - Run shell command.
  • bool confirmPropt(std::string_view message) - Shows message and asks for y/N from user.
  • bool changeMode(std::string_view file, mode_t mode) - Change file permissions.
  • bool changeOwner(std::string_view file, uid_t uid, gid_t gid) - Change file owner (user ID and group ID).
  • std::string currentWorkingDirectory() - Get current working directory as string. Returns empty string on error.
  • std::string currentDate() - Get current date as string (format: YYYY-MM-DD). Returns empty string on error.
  • std::string currentTime() - Get current time as string (format: HH:MM:SS). Returns empty string on error.
  • std::pair<std::string, int> runCommandWithOutput(std::string_view cmd) - Run shell command return output as string. Returns std::pair<std::string, int>.
  • std::string pathJoin(std::string base, std::string relative) - Joins base path with relative path and returns result.
  • std::string pathBasename(std::string_view entry) - Get the filename part of given path.
  • std::string pathDirname(std::string_view entry) - Get the directory part of given path.
  • uint64_t getRandomOffset(uint64_t size, uint64_t bufferSize) - Get random offset depending on size and bufferSize.
  • int convertTo(uint64_t size, sizeCastTypes type) - Convert size to multiple. Returns result as int.
  • std::string multipleToString(sizeCastTypes type) - Convert input multiple variable to string.
  • std::string format(const char *format, ...) - Format it input and return as string.

Android-Specif

  • bool androidReboot(std::string_view arg) - Reboot device to arg.
  • std::string getProperty(std::string_view prop) - Read prop property and return.

Compling and linking

If you're using CMake in your project, you can include it directly with add_subdirectory. Both the static and shared libraries will be compiled.

# Include libhelper library
add_subdirectory(srclib/libhelper)

# Usage example
add_executable(main main.cpp)
target_link_libraries(main PRIVATE helper_shared) # use helper_static if you want link static library

If you're going to use it prebuilt, you can find it in the PMT releases. Or you can compile it separately... WARNING: PMT releases only include builds for ARM.


libpartition_map library

libpartition_map provides a C++ interface to manage, query, and manipulate disk partitions programmatically. It is built on top of libhelper.


Macros

There aren't many macros.

// You can take a look also at PMT functions for usage examples...
// Definitely use this when using lambdas with do***
#define COMMON_LAMBDA_PARAMS                                                   \
  (const std::string &partition, const PartitionMap::BasicInf props)

auto func = [] COMMON_LAMDA_PARAMS -> bool { /* Code... */ };

Namespaces

PartitionMap

Main namespace of the library. Contains all core types, builder classes, and utilities.

#include <libpartition_map/lib.hpp>

Types

Info

Represents a single partition entry.

Member Type Description
name std::string Partition name
props struct Partition properties
struct _entry {
  std::string name;
  struct {
    uint64_t size;
    bool isLogical;
  } props;
};

BasicInfo

Minimal information about a partition.

Member Type Description
size uint64_t Partition size
isLogical bool Logical partition flag

Aliases

Alias Type
Partition_t _entry
Map_t basic_partition_map
BuildMap / Map basic_partition_map_builder
BasicInf _returnable_entry
Info _entry
Error Helper::Error

Classes

Map_t

Core partition map type. Map_t is alias of basic_partition_map.

Overview
PartitionMap::Map_t myMap;
  • Supports insertion, merging, clearing, and queries etc...
  • Provides for-each support via iterator and constant_iterator:
for (const auto &entry : myMap) {
  std::cout << entry.first << " size: " << entry.second.size << " logical: " << entry.second.isLogical << std::endl;
}

Note: Direct use of iterator and constant_iterator is typically unnecessary; use range-based for loops.

Members
  • _entry *_data: Pointer to internal array of partitions.
  • size_t _count, _capacity: Internal counters.
Methods
  • insert(name, size, logical): Insert a partition.
  • merge(other): Merge another map.
  • clear(): Clear all entries.
  • get_size(name), is_logical(name), get_all(name): Retrieve partition info.
  • find(name), find_(name): Check existence.
  • size(), empty(): Map size and empty check.
Operators
  • operator std::vector<Info>(): Returns list as vector.
  • operator int(): Returns partition count.
  • operator bool(): Success check (whether it is not empty).
  • operator=(&map): Equal operator.
  • operator!(): Failure check (whether it is empty).
  • operator()(path): Build map from path.
  • Info operator[](index): Return the information of the section in the input index in the Info structure.
  • BasicInf operator[](name): Return the input section name information in the BasicInfo structure.

BuildMap

Interface to build and query partition maps. BuildMap is alias of basic_partition_map_builder.

Members
  • Map_t _current_map: Current map.
  • std::string _workdir: Search directory.
  • bool _any_generating_error, _map_builded: Status flags.
Core Methods
  • readDirectory(path): Build map from a directory.
  • readDefaultDirectories(): Build map from default /dev entries.
  • getAll(): Returns the current Map_t map.
  • get(name): Returns optional info (size, isLogical).
  • getLogicalPartitionList(), getPhysicalPartitionList(), getPartitionList(): Return partition lists.
  • getRealLinkPathOf(name), getRealPathOf(name): Returns path.
  • hasPartition(name), isLogical(name), sizeOf(name), empty(): Info queries.
  • copyPartitionsToVector(vec), copyLogicalPartitionsToVector(vec), copyPhysicalPartitionsToVector(vec): Copy lists to vectors.
doFor*** Methods
  • doForAllPartitions(func)
  • doForPhysicalPartitions(func)
  • doForLogicalPartitions(func)
  • doForPartitionList(list, func)
Operators
  • operator*(): Returns reference to internal map.
  • operator std::vector<Info>(): Returns list as vector.
  • operator int(): Returns partition count.
  • operator std::string(): Returns working directory.
  • operator bool(): Success check.
  • operator!(): Failure check.
  • operator()(path): Build map from path.
  • Info operator[](index): Return the information of the section in the input index in the Info structure.
  • BasicInf operator[](name): Return the input section name information in the BasicInfo structure.
Example Usage
#include <libpartition_map/lib.hpp>
#include <iostream>
#include <vector>
#include <list>
#include <string>

int main() {
  try {
    // -------------------------------
    // Builder usage
    // -------------------------------
    PartitionMap::BuildMap builder; // Reads default dirs

    // Build map from default directories
    if (!builder.readDefaultDirectories()) {
      std::cerr << "Failed to read default directories.\n";
      return 1;
    }

    // Build map from a specific directory
    if (!builder.readDirectory("/dev/block/by-name")) {
      std::cerr << "Failed to read /dev/block/by-name\n";
    }

    // -------------------------------
    // Accessing the map
    // -------------------------------
    PartitionMap::Map_t map = *builder;

    // Check if a partition exists
    if (builder.hasPartition("boot")) {
      std::cout << "Partition boot exists\n";
    }

    // Check if a partition is logical
    if (builder.isLogical("system")) {
      std::cout << "Partition system is logical\n";
    }

    // Get partition size
    uint64_t size = builder.sizeOf("boot");
    std::cout << "Size of boot: " << size << " bytes\n";

    // Get partition info (size + logical)
    auto partInfo = builder.get("boot");
    if (partInfo) {
      std::cout << "boot - size: " << partInfo->first
                << ", logical: " << (partInfo->second ? "yes" : "no") << "\n";
    }

    // Get lists
    auto allParts = builder.getPartitionList();
    auto logicalParts = builder.getLogicalPartitionList();
    auto physicalParts = builder.getPhysicalPartitionList();

    if (allParts) {
      std::cout << "All partitions:\n";
      for (const auto &p : *allParts)
        std::cout << "  " << p << "\n";
    }

    if (logicalParts) {
      std::cout << "Logical partitions:\n";
      for (const auto &p : *logicalParts)
        std::cout << "  " << p << "\n";
    }

    if (physicalParts) {
      std::cout << "Physical partitions:\n";
      for (const auto &p : *physicalParts)
        std::cout << "  " << p << "\n";
    }

    // -------------------------------
    // Lambda examples
    // -------------------------------
    builder.doForAllPartitions([](const std::string &name, PartitionMap::BasicInf info) {
      std::cout << "Partition: " << name
                << " size: " << info.size
                << " logical: " << (info.isLogical ? "yes" : "no") << "\n";
      return true;
    });

    builder.doForPhysicalPartitions([](const std::string &name, PartitionMap::BasicInf info) {
      std::cout << "[Physical] " << name << "\n";
      return true;
    });

    builder.doForLogicalPartitions([](const std::string &name, PartitionMap::BasicInf info) {
      std::cout << "[Logical] " << name << "\n";
      return true;
    });

    std::vector<std::string> partitionVec;
    builder.copyPartitionsToVector(partitionVec);

    std::cout << "Copied partitions to vector:\n";
    for (auto &p : partitionVec)
      std::cout << "  " << p << "\n";

    // -------------------------------
    // Map operators
    // -------------------------------
    int count = map;
    std::cout << "Total partitions: " << count << "\n";

    std::vector<PartitionMap::Info> infoVec = map;
    for (auto &info : infoVec) {
      std::cout << "Partition: " << info.name
                << " size: " << info.props.size
                << " logical: " << (info.props.isLogical ? "yes" : "no") << "\n";
    }

    // -------------------------------
    // For-each support (iterator)
    // -------------------------------
    for (auto &[name, props] : map) {
      std::cout << "[Iterator] " << name
                << " size: " << props.size
                << " logical: " << (props.isLogical ? "yes" : "no") << "\n";
    }

  } catch (const PartitionMap::Error &e) {
    std::cerr << "PartitionMap error: " << e.message() << "\n";
  }

  return 0;
}

Note: PartitionMap::Error can be thrown, so always wrap operations in try-catch blocks.


Constants

PartitionMap::Extras::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;
// ... and more

PartitionMap::Extras::AndroidMagic

constexpr uint64_t BOOT_IMAGE = 0x2144494F52444E41;
constexpr uint64_t VBOOT_IMAGE = 0x544F4F4252444E56;
constexpr uint64_t LK_IMAGE = 0x00006B6C;
// ... and more

There are also maps that keep these ready.

extern std::map<uint64_t, std::string> FileSystemMagicMap;
extern std::map<uint64_t, std::string> AndroidMagicMap;
extern std::map<uint64_t, std::string> MagicMap;

Compling and linking

If you're using CMake in your project, you can include it directly with add_subdirectory. Both the static and shared libraries will be compiled.

# Include required libhelper library
add_subdirectory(srclib/libhelper)
add_subdirectory(srclib/libpartition_map)

# Usage example
add_executable(main main.cpp)
target_link_libraries(main PRIVATE partition_map_shared) # use partition_map_static if you want link static library

If you're going to use it prebuilt, you can find it in the PMT releases. Or you can compile it separately... WARNING: PMT releases only include builds for ARM.