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

@@ -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,268 +22,305 @@
#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;
struct _entry {
std::string name;
struct {
uint64_t size;
bool isLogical;
} props;
};
/**
* The main type of the library. The Builder class is designed
* to be easily manipulated and modified only on this class.
*/
class basic_partition_map final {
private:
void _resize_map();
[[nodiscard]] int _index_of(std::string_view name) const;
public:
_entry* _data;
size_t _count{}, _capacity{};
struct _returnable_entry {
uint64_t size;
bool isLogical;
struct {
uint64_t size;
bool isLogical;
} props;
};
using BasicInf = _returnable_entry;
/**
* The main type of the library. The Builder class is designed
* to be easily manipulated and modified only on this class.
*/
class basic_partition_map final {
private:
void _resize_map();
basic_partition_map(const std::string& name, uint64_t size, bool logical);
basic_partition_map(const basic_partition_map& other);
basic_partition_map();
~basic_partition_map();
[[nodiscard]] int _index_of(std::string_view name) const;
bool insert(const std::string& name, uint64_t size, bool logical);
void merge(const basic_partition_map& map);
[[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;
[[nodiscard]] bool find(std::string_view name) const;
[[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;
class iterator {
public:
_entry* ptr;
_entry *_data;
size_t _count{}, _capacity{};
explicit iterator(_entry* p);
struct _returnable_entry {
uint64_t size;
bool isLogical;
};
auto operator*() const -> std::pair<std::string&, decltype(_entry::props)&>;
_entry* operator->() const;
iterator& operator++();
iterator operator++(int);
bool operator!=(const iterator& other) const;
bool operator==(const iterator& other) const;
using BasicInf = _returnable_entry;
basic_partition_map(const std::string &name, uint64_t size, bool logical);
basic_partition_map(const basic_partition_map &other);
basic_partition_map();
~basic_partition_map();
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;
[[nodiscard]] bool find(std::string_view name) const;
[[nodiscard]] std::string find_(const std::string &name) const;
[[nodiscard]] size_t size() const;
[[nodiscard]] bool empty() const;
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;
class iterator {
public:
_entry *ptr;
explicit iterator(_entry *p);
auto operator*() const -> std::pair<std::string &, decltype(_entry::props) &>;
_entry *operator->() const;
iterator &operator++();
iterator operator++(int);
bool operator!=(const iterator &other) const;
bool operator==(const iterator &other) const;
};
class constant_iterator {
public:
const _entry *ptr;
explicit constant_iterator(const _entry *p);
auto operator*() const -> std::pair<const std::string &, const decltype(_entry::props) &>;
const _entry *operator->() const;
constant_iterator &operator++();
constant_iterator operator++(int);
bool operator!=(const constant_iterator &other) const;
bool operator==(const constant_iterator &other) const;
};
/* for-each support */
[[nodiscard]] iterator begin() const;
[[nodiscard]] iterator end() const;
[[nodiscard]] constant_iterator cbegin() const;
[[nodiscard]] constant_iterator cend() const;
};
class constant_iterator {
using Map_t = basic_partition_map;
class basic_partition_map_builder final {
private:
Map_t _current_map;
std::string _workdir;
bool _any_generating_error, _map_builded;
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:
const _entry* ptr;
/**
* By default, it searches the directories in the
* defaultEntryList in PartitionMap.cpp in order and
* uses the directory it finds.
*/
basic_partition_map_builder();
explicit constant_iterator(const _entry* p);
/**
* A constructor with input. Need search path
*/
explicit basic_partition_map_builder(std::string_view path);
auto operator*() const -> std::pair<const std::string&, const decltype(_entry::props)&>;
const _entry* operator->() const;
constant_iterator& operator++();
constant_iterator operator++(int);
bool operator!=(const constant_iterator& other) const;
bool operator==(const constant_iterator& other) const;
/**
* Returns the current list content in Map_t type.
* If no list is created, returns std::nullopt.
*/
[[nodiscard]] Map_t getAll() const;
/**
* Returns information of a specific partition in
* Map_temp_t type. If the partition is not in the
* currently created list, returns std::nullopt.
*/
[[nodiscard]] std::optional<std::pair<uint64_t, bool> > get(std::string_view name) const;
/**
* If there is a logical partition(s) in the created
* list, it returns a list of type std::list (containing
* data of type std::string). If there is no logical
* partition in the created list, it returns std::nullopt.
*/
[[nodiscard]] std::optional<std::list<std::string> > getLogicalPartitionList() const;
/**
* The physical partitions in the created list are
* returned as std::list type. If there is no content
* due to any problem, returns std::nullopt.
*/
[[nodiscard]] std::optional<std::list<std::string> > getPhysicalPartitionList() const;
/**
* The partitions in the created list are returned as std::list
* If there is no content due to any problem, returns std::nullopt
*/
[[nodiscard]] std::optional<std::list<std::string> > getPartitionList() const;
/**
* Returns the full link path of the entered partition
* name in the current search directory as std::string.
* If the partition is not in the list, an empty
* std::string is returned.
*/
[[nodiscard]] std::string getRealLinkPathOf(std::string_view name) const;
/**
* Returns the actual path of the partition as
* std::string. Like /dev/block/sda5
*/
[[nodiscard]] std::string getRealPathOf(std::string_view name) const;
/**
* If it exists, the path to the search string is
* returned as std::string. If it does not exist,
* an empty std::string is returned.
*/
[[nodiscard]] std::string getCurrentWorkDir() const;
/**
* Returns whether the entered partition name is in the
* created partition list as a bool.
*/
[[nodiscard]] bool hasPartition(std::string_view name) const;
/**
* Returns the bool type status of whether the
* entered partition name is marked as logical in the
* created list. Alternatively, the current partition
* information can be retrieved with the get() function
* and checked for logicality.
*/
[[nodiscard]] bool isLogical(std::string_view name) const;
/**
* The created list and the current search index name are cleared.
*/
void clear();
/**
* The entered path is defined as the new search
* directory and the search is performed in the entered
* directory. If everything goes well, true is returned.
*/
bool readDirectory(std::string_view path);
/**
* Reads default /dev entries and builds map.
*/
bool readDefaultDirectories();
/**
* Whether the current list is empty or not is returned
* as bool type. If there is content in the list, true
* is returned, otherwise false is returned.
*/
[[nodiscard]] bool empty() const;
/**
* If it exists, the size of the partition with the
* entered name is returned as uint64_t type.
* If it does not exist, 0 is returned.
*/
[[nodiscard]] uint64_t sizeOf(std::string_view name) const;
/**
* If the content lists of the two created objects are
* the same (checked only according to the partition
* names), true is returned, otherwise false is returned
*/
friend bool operator==(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs);
/**
* The opposite logic of the == operator.
*/
friend bool operator!=(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs);
/**
* You can check whether the object was created
* successfully. If the problem did not occur, true is
* returned, if it did, false is returned.
*/
explicit operator bool() const;
/**
* Returns true if the object creation failed (i.e., there's a problem),
* and false if the object is correctly created.
*/
bool operator!() const;
/**
* Build map with input path. Implementation of readDirectory().
*/
bool operator()(std::string_view path);
};
/* for-each support */
[[nodiscard]] iterator begin() const;
[[nodiscard]] iterator end() const;
[[nodiscard]] constant_iterator cbegin() const;
[[nodiscard]] constant_iterator cend() const;
};
using Map_t = basic_partition_map;
class basic_partition_map_builder final {
private:
Map_t _current_map;
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]] uint64_t _get_size(const std::string& path);
public:
/**
* By default, it searches the directories in the
* defaultEntryList in PartitionMap.cpp in order and
* uses the directory it finds.
*/
basic_partition_map_builder();
using Error = Helper::Error;
/**
* A constructor with input. Need search path
* To get the version information of libpartition_map
* library. It is returned as std::string type.
*/
explicit basic_partition_map_builder(std::string_view path);
std::string getLibVersion();
/**
* Returns the current list content in Map_t type.
* If no list is created, returns std::nullopt.
*/
[[nodiscard]] Map_t getAll() const;
using BuildMap = basic_partition_map_builder;
using Map = basic_partition_map_builder;
/**
* Returns information of a specific partition in
* Map_temp_t type. If the partition is not in the
* currently created list, returns std::nullopt.
*/
[[nodiscard]] std::optional<std::pair<uint64_t, bool>> get(std::string_view name) const;
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
/**
* If there is a logical partition(s) in the created
* list, it returns a list of type std::list (containing
* data of type std::string). If there is no logical
* partition in the created list, it returns std::nullopt.
*/
[[nodiscard]] std::optional<std::list<std::string>> getLogicalPartitionList() const;
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
/**
* The physical partitions in the created list are
* returned as std::list type. If there is no content
* due to any problem, returns std::nullopt.
*/
[[nodiscard]] std::optional<std::list<std::string>> getPhysicalPartitionList() const;
/**
* The partitions in the created list are returned as std::list
* If there is no content due to any problem, returns std::nullopt
*/
[[nodiscard]] std::optional<std::list<std::string>> getPartitionList() const;
/**
* Returns the full link path of the entered partition
* name in the current search directory as std::string.
* If the partition is not in the list, an empty
* std::string is returned.
*/
[[nodiscard]] std::string getRealLinkPathOf(std::string_view name) const;
/**
* Returns the actual path of the partition as
* std::string. Like /dev/block/sda5
*/
[[nodiscard]] std::string getRealPathOf(std::string_view name) const;
/**
* If it exists, the path to the search string is
* returned as std::string. If it does not exist,
* an empty std::string is returned.
*/
[[nodiscard]] std::string getCurrentWorkDir() const;
/**
* Returns whether the entered partition name is in the
* created partition list as a bool.
*/
[[nodiscard]] bool hasPartition(std::string_view name) const;
/**
* Returns the bool type status of whether the
* entered partition name is marked as logical in the
* created list. Alternatively, the current partition
* information can be retrieved with the get() function
* and checked for logicality.
*/
[[nodiscard]] bool isLogical(std::string_view name) const;
/**
* The created list and the current search index name are cleared.
*/
void clear();
/**
* The entered path is defined as the new search
* directory and the search is performed in the entered
* directory. If everything goes well, true is returned.
*/
bool readDirectory(std::string_view path);
/**
* Reads default /dev entries and builds map.
*/
bool readDefaultDirectories();
/**
* Whether the current list is empty or not is returned
* as bool type. If there is content in the list, true
* is returned, otherwise false is returned.
*/
[[nodiscard]] bool empty() const;
/**
* If it exists, the size of the partition with the
* entered name is returned as uint64_t type.
* If it does not exist, 0 is returned.
*/
[[nodiscard]] uint64_t sizeOf(std::string_view name) const;
/**
* If the content lists of the two created objects are
* the same (checked only according to the partition
* names), true is returned, otherwise false is returned
*/
friend bool operator==(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs);
/**
* The opposite logic of the == operator.
*/
friend bool operator!=(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs);
/**
* You can check whether the object was created
* successfully. If the problem did not occur, true is
* returned, if it did, false is returned.
*/
explicit operator bool() const;
/**
* Returns true if the object creation failed (i.e., there's a problem),
* and false if the object is correctly created.
*/
bool operator!() const;
/**
* Build map with input path. Implementation of readDirectory().
*/
bool operator()(std::string_view path);
};
using Error = Helper::Error;
/**
* To get the version information of libpartition_map
* library. It is returned as std::string type.
*/
std::string getLibVersion();
using BuildMap = basic_partition_map_builder;
using Map = basic_partition_map_builder;
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,78 +20,71 @@
#include <libpartition_map/lib.hpp>
namespace PartitionMap {
Map_t basic_partition_map_builder::getAll() const {
_map_build_check();
return _current_map;
}
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 {
_map_build_check();
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));
}
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 {
_map_build_check();
std::optional<std::list<std::string>> basic_partition_map_builder::getLogicalPartitionList() const
{
_map_build_check();
std::list<std::string> logicals;
for (const auto &[name, props]: _current_map)
if (props.isLogical) logicals.push_back(name);
std::list<std::string> logicals;
for (const auto& [name, props] : _current_map)
if (props.isLogical) logicals.push_back(name);
if (logicals.empty()) return std::nullopt;
return logicals;
}
if (logicals.empty()) return std::nullopt;
return logicals;
}
std::optional<std::list<std::string> > basic_partition_map_builder::getPhysicalPartitionList() const {
_map_build_check();
std::optional<std::list<std::string>> basic_partition_map_builder::getPhysicalPartitionList() const
{
_map_build_check();
std::list<std::string> physicals;
for (const auto &[name, props]: _current_map)
if (!props.isLogical) physicals.push_back(name);
std::list<std::string> physicals;
for (const auto& [name, props] : _current_map)
if (!props.isLogical) physicals.push_back(name);
if (physicals.empty()) return std::nullopt;
return physicals;
}
if (physicals.empty()) return std::nullopt;
return physicals;
}
std::optional<std::list<std::string> > basic_partition_map_builder::getPartitionList() const {
_map_build_check();
std::optional<std::list<std::string>> basic_partition_map_builder::getPartitionList() const {
_map_build_check();
std::list<std::string> partitions;
for (const auto &[name, props]: _current_map) partitions.push_back(name);
std::list<std::string> partitions;
for (const auto& [name, props] : _current_map) partitions.push_back(name);
if (partitions.empty()) return std::nullopt;
return partitions;
}
if (partitions.empty()) return std::nullopt;
return partitions;
}
std::string basic_partition_map_builder::getRealLinkPathOf(const std::string_view name) const {
_map_build_check();
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());
}
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 {
_map_build_check();
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();
if (!_current_map.find(name)
|| !std::filesystem::is_symlink(full))
return {};
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 {};
return std::filesystem::read_symlink(full);
}
std::string basic_partition_map_builder::getCurrentWorkDir() const
{
return _workdir;
}
return std::filesystem::read_symlink(full);
}
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,216 +39,197 @@ 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)
{
if (path.find("/block/") == std::string::npos) {
LOGN(MAP, ERROR) << "Path " << path << " is not a real block directory.";
return false;
}
return true;
}
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::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;
for (const auto& entry : entries) {
if (entry.path().filename() != "by-uuid"
&& std::string(entry.path()).find("com.") == std::string::npos)
map.insert(entry.path().filename().string(), _get_size(entry.path()), logical);
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;
}
return true;
}
LOGN(MAP, INFO) << std::boolalpha << "Map generated successfully. is_logical_map=" << logical << std::endl;
return map;
}
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::sort(entries.begin(), entries.end(), [](const auto &a, const auto &b) {
return a.path().filename() < b.path().filename();
});
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);
}
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)
map.insert(entry.path().filename().string(), _get_size(entry.path()), logical);
}
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)
{
const std::string real = std::filesystem::read_symlink(path);
const int fd = open(real.data(), O_RDONLY);
if (fd < 0) {
LOGN(MAP, ERROR) << "Cannot open " << real << ": " << strerror(errno) << std::endl;
return 0;
LOGN(MAP, INFO) << std::boolalpha << "Map generated successfully. is_logical_map=" << logical << std::endl;
return map;
}
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;
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);
}
close(fd);
return size;
}
void basic_partition_map_builder::_map_build_check() const {
if (!_map_builded)
throw Error("Please build partition map before!");
}
basic_partition_map_builder::basic_partition_map_builder()
{
LOGN(MAP, INFO) << "default constructor called. Starting build." << std::endl;
uint64_t basic_partition_map_builder::_get_size(const std::string &path) {
const std::string real = std::filesystem::read_symlink(path);
Helper::garbageCollector collector;
for (const auto& path : defaultEntryList) {
if (std::filesystem::exists(path)) {
_current_map = _build_map(path);
if (_current_map.empty()) {
_any_generating_error = true;
} else {
_workdir = path;
break;
const int fd = Helper::openAndAddToCloseList(real, collector, O_RDONLY);
if (fd < 0) {
LOGN(MAP, ERROR) << "Cannot open " << real << ": " << strerror(errno) << std::endl;
return 0;
}
uint64_t size = 0;
if (ioctl(fd, BLKGETSIZE64, &size) != 0) {
LOGN(MAP, ERROR) << "ioctl() process failed for " << real << ": " << strerror(errno) << std::endl;
return 0;
}
return size;
}
basic_partition_map_builder::basic_partition_map_builder() {
LOGN(MAP, INFO) << "default constructor called. Starting build." << std::endl;
for (const auto &path: defaultEntryList) {
if (std::filesystem::exists(path)) {
_current_map = _build_map(path);
if (_current_map.empty()) {
_any_generating_error = true;
} else {
_workdir = path;
break;
}
}
}
if (_current_map.empty())
LOGN(MAP, ERROR) << "Cannot build map by any default search entry." << std::endl;
LOGN(MAP, INFO) << "default constructor successfully ended work." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
}
if (_current_map.empty())
LOGN(MAP, ERROR) << "Cannot build map by any default search entry." << std::endl;
basic_partition_map_builder::basic_partition_map_builder(const std::string_view path) {
LOGN(MAP, INFO) << "argument-based constructor called. Starting build." << std::endl;
LOGN(MAP, INFO) << "default constructor successfully ended work." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
}
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)) {
if (!_is_real_block_dir(path)) return;
_current_map = _build_map(path);
if (_current_map.empty()) _any_generating_error = true;
else _workdir = path;
} else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data());
LOGN(MAP, INFO) << "argument-based constructor successfully ended work." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
}
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
{
_map_build_check();
return _current_map.is_logical(name);
}
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)
{
_map_builded = false;
LOGN(MAP, INFO) << "read " << path << " directory request." << std::endl;
if (std::filesystem::exists(path)) {
if (!_is_real_block_dir(path)) return false;
_current_map = _build_map(path);
if (_current_map.empty()) {
_any_generating_error = true;
return false;
} else _workdir = path;
} else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data());
LOGN(MAP, INFO) << "read " << path << " successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
return true;
}
bool basic_partition_map_builder::readDefaultDirectories()
{
_map_builded = false;
LOGN(MAP, INFO) << "read default directories request." << std::endl;
for (const auto& path : defaultEntryList) {
if (std::filesystem::exists(path)) {
if (!_is_real_block_dir(path)) return;
_current_map = _build_map(path);
if (_current_map.empty()) _any_generating_error = true;
else _workdir = path;
} else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data());
LOGN(MAP, INFO) << "argument-based constructor successfully ended work." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
}
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 {
_map_build_check();
return _current_map.is_logical(name);
}
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) {
_map_builded = false;
LOGN(MAP, INFO) << "read " << path << " directory request." << std::endl;
if (std::filesystem::exists(path)) {
if (!_is_real_block_dir(path)) return false;
_current_map = _build_map(path);
if (_current_map.empty()) {
_any_generating_error = true;
return false;
} else {
_workdir = path;
break;
}
}
} else _workdir = path;
} else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data());
LOGN(MAP, INFO) << "read " << path << " successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
return true;
}
if (_current_map.empty())
LOGN(MAP, ERROR) << "Cannot build map by any default search entry." << std::endl;
bool basic_partition_map_builder::readDefaultDirectories() {
_map_builded = false;
LOGN(MAP, INFO) << "read default directories request." << std::endl;
LOGN(MAP, INFO) << "read default directories successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
return true;
}
for (const auto &path: defaultEntryList) {
if (std::filesystem::exists(path)) {
_current_map = _build_map(path);
if (_current_map.empty()) {
_any_generating_error = true;
return false;
} else {
_workdir = path;
break;
}
}
}
bool basic_partition_map_builder::empty() const
{
_map_build_check();
return _current_map.empty();
}
if (_current_map.empty())
LOGN(MAP, ERROR) << "Cannot build map by any default search entry." << std::endl;
uint64_t basic_partition_map_builder::sizeOf(const std::string_view name) const
{
_map_build_check();
return _current_map.get_size(name);
}
LOGN(MAP, INFO) << "read default directories successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
return true;
}
bool operator==(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs)
{
return lhs._current_map == rhs._current_map;
}
bool basic_partition_map_builder::empty() const {
_map_build_check();
return _current_map.empty();
}
bool operator!=(const basic_partition_map_builder& lhs, const basic_partition_map_builder& rhs)
{
return !(lhs == rhs);
}
uint64_t basic_partition_map_builder::sizeOf(const std::string_view name) const {
_map_build_check();
return _current_map.get_size(name);
}
basic_partition_map_builder::operator bool() const
{
return !this->_any_generating_error;
}
bool operator==(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs) {
return lhs._current_map == rhs._current_map;
}
bool basic_partition_map_builder::operator!() const
{
return this->_any_generating_error;
}
bool operator!=(const basic_partition_map_builder &lhs, const basic_partition_map_builder &rhs) {
return !(lhs == rhs);
}
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);
}
basic_partition_map_builder::operator bool() const {
return !this->_any_generating_error;
}
std::string getLibVersion()
{
MKVERSION("libpartition_map");
}
bool basic_partition_map_builder::operator!() const {
return this->_any_generating_error;
}
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() {
MKVERSION("libpartition_map");
}
} // namespace PartitionMap

View File

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