From d65867c249eff63f7f3409456be7c99ded4fd181 Mon Sep 17 00:00:00 2001 From: YZBruh Date: Mon, 21 Jul 2025 12:08:45 +0300 Subject: [PATCH] pmt: first codes. --- .vscode/c_cpp_properties.json | 12 + CMakeLists.txt | 36 ++ build.sh | 92 +++++ include/PartitionManager/lib.hpp | 30 ++ src/.placeholder | 0 srclib/libhelper/CMakeLists.txt | 41 ++ srclib/libhelper/include/libhelper/lib.hpp | 186 +++++++++ srclib/libhelper/include/picosha2.h | 377 ++++++++++++++++++ srclib/libhelper/src/Checkers.cpp | 83 ++++ srclib/libhelper/src/Classes.cpp | 96 +++++ srclib/libhelper/src/FileUtil.cpp | 246 ++++++++++++ srclib/libhelper/src/Sha256.cpp | 54 +++ srclib/libhelper/src/Utilities.cpp | 140 +++++++ srclib/libhelper/tests/test.cpp | 101 +++++ srclib/libhelper/tests/test.sh | 23 ++ srclib/libpartition_map/CMakeLists.txt | 41 ++ .../include/libpartition_map/lib.hpp | 332 +++++++++++++++ srclib/libpartition_map/src/Getters.cpp | 87 ++++ srclib/libpartition_map/src/PartitionMap.cpp | 209 ++++++++++ srclib/libpartition_map/src/Type.cpp | 278 +++++++++++++ srclib/libpartition_map/tests/test.cpp | 78 ++++ tests/test.cpp | 0 22 files changed, 2542 insertions(+) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 CMakeLists.txt create mode 100644 build.sh create mode 100644 include/PartitionManager/lib.hpp create mode 100644 src/.placeholder create mode 100644 srclib/libhelper/CMakeLists.txt create mode 100644 srclib/libhelper/include/libhelper/lib.hpp create mode 100644 srclib/libhelper/include/picosha2.h create mode 100644 srclib/libhelper/src/Checkers.cpp create mode 100644 srclib/libhelper/src/Classes.cpp create mode 100644 srclib/libhelper/src/FileUtil.cpp create mode 100644 srclib/libhelper/src/Sha256.cpp create mode 100644 srclib/libhelper/src/Utilities.cpp create mode 100644 srclib/libhelper/tests/test.cpp create mode 100644 srclib/libhelper/tests/test.sh create mode 100644 srclib/libpartition_map/CMakeLists.txt create mode 100644 srclib/libpartition_map/include/libpartition_map/lib.hpp create mode 100644 srclib/libpartition_map/src/Getters.cpp create mode 100644 srclib/libpartition_map/src/PartitionMap.cpp create mode 100644 srclib/libpartition_map/src/Type.cpp create mode 100644 srclib/libpartition_map/tests/test.cpp create mode 100644 tests/test.cpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..67edf50 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,12 @@ +{ + "configurations": [ + { + "includePath": [ + "${workspaceFolder}/srclib/libhelper/include", + "${workspaceFolder}/srclib/libpartition_map/include", + "${workspaceFolder}/include" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1f3a809 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# 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. +# + +# Project info +cmake_minimum_required(VERSION 3.10) +project(pmt VERSION 1.0.0) + +set(DEBUG_FLAGS -gdwarf-5 -fsanitize=address -fstack-protector -O0) + +# Add compiler flag based on build type +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DEBUG_FLAGS}") + set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} ${DEBUG_FLAGS}") +endif() + +# Add include directories +include_directories(include srclib/libhelper/include srclib/libpartition_map/include) + +# Add libraries +add_subdirectory(srclib/libhelper) +add_subdirectory(srclib/libpartition_map) + +# NOTE: pmt is not ready, this CMakeFiles.txt only builds libraries diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..7028e7b --- /dev/null +++ b/build.sh @@ -0,0 +1,92 @@ +#!/usr/bin/bash +# +# Copyright 2025 Yağız Zengin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -e + +BUILD_64="build_arm64-v8a" +BUILD_32="build_armeabi-v7a" +THIS="$(basename $0)" + +echo() +{ + command echo "[$THIS]: $*" +} + +checks() +{ + if [ -z "$ANDROID_NDK" ]; then + echo "Please set ANDROID_NDK variable as your NDK path." + exit 1 + fi + if [ ! -f /usr/bin/cmake ] && [ ! -f /bin/cmake ]; then + echo "Please verify your CMake installation." + exit 1 + fi +} + +clean() +{ + echo "Cleaning workspace." + rm -rf $BUILD_32 $BUILD_64 srclib/libhelper/tests/dir srclib/libhelper/tests/linkdir srclib/libhelper/tests/file.txt +} + +build() +{ + mkdir -p $BUILD_64 $BUILD_32 + command echo -e "BUILD INFO: + ARCHS: arm64-v8a armeabi-v7a + ANDROID_PLATFORM: $ANDROID_PLATFORM + ANDROID_TOOLCHAIN_FILE: $ANDROID_NDK/build/cmake/android.toolchain.cmake\n" + + echo "Configuring for arm64-v8a..." + cmake -B $BUILD_64 -S . $1 \ + -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=$ANDROID_PLATFORM + + echo "Configuring for armeabi-v7a..." + cmake -B $BUILD_32 -S . $1 \ + -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=armeabi-v7a \ + -DANDROID_PLATFORM=$ANDROID_PLATFORM + + echo "Building arm64-v8a artifacts..." + cmake --build $BUILD_64 + echo "arm64-v8a build complete, artifacts: $PWD/$BUILD_64" + + echo "Building armeabi-v7a artifacts..." + cmake --build $BUILD_32 + echo "armeabi-v7a build complete, artifacts: $PWD/$BUILD_32" +} + +if [ $# -eq 0 ]; then + command echo "Usage: $0 build|rebuild|clean [EXTRA_CMAKE_FLAGS] [ANDROID_PLATFORM=SELECTED_ANDROID_PLATFORM]" + exit 1 +fi + +if [ -z $ANDROID_PLATFORM ]; then ANDROID_PLATFORM="android-21"; fi + +checks + +case $1 in + "build") build $2;; + "clean") clean ;; + "rebuild") clean; build $2;; + *) + command echo "$0: Unknown argument: $1" + exit 1 ;; +esac diff --git a/include/PartitionManager/lib.hpp b/include/PartitionManager/lib.hpp new file mode 100644 index 0000000..7560c2e --- /dev/null +++ b/include/PartitionManager/lib.hpp @@ -0,0 +1,30 @@ +/* + 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. +*/ + +#ifndef LIBPMT_LIB_HPP +#define LIBPMT_LIB_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace PartitionManager {} // namespace PartitionManager + +#endif // #ifndef LIBPMT_LIB_HPP diff --git a/src/.placeholder b/src/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/srclib/libhelper/CMakeLists.txt b/srclib/libhelper/CMakeLists.txt new file mode 100644 index 0000000..cefcdba --- /dev/null +++ b/srclib/libhelper/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# Copyright 2025 Yağız Zengin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set(LIBHELPER_FLAGS -Wall -DLIB_BUILD_MODE) +set(LIBHELPER_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/Checkers.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Classes.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/FileUtil.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Sha256.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Utilities.cpp +) + +# Add targets +add_library(helper_shared SHARED ${LIBHELPER_SOURCES}) +add_library(helper_static STATIC ${LIBHELPER_SOURCES}) +add_executable(libhelper_test tests/test.cpp) + +# Set compiler flags +target_compile_options(helper_shared PRIVATE ${LIBHELPER_FLAGS}) +target_compile_options(helper_static PRIVATE ${LIBHELPER_FLAGS}) +target_compile_options(libhelper_test PRIVATE ${LIBHELPER_FLAGS}) +target_link_libraries(libhelper_test PRIVATE helper_shared) +target_link_options(libhelper_test PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") +target_link_options(helper_shared PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") + +# Set appropriate output names +set_target_properties(helper_shared PROPERTIES OUTPUT_NAME "helper") +set_target_properties(helper_static PROPERTIES OUTPUT_NAME "helper") diff --git a/srclib/libhelper/include/libhelper/lib.hpp b/srclib/libhelper/include/libhelper/lib.hpp new file mode 100644 index 0000000..db97da4 --- /dev/null +++ b/srclib/libhelper/include/libhelper/lib.hpp @@ -0,0 +1,186 @@ +/* + 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. +*/ + +#ifndef LIBHELPER_LIB_HPP +#define LIBHELPER_LIB_HPP + +#define LIBHELPER_MAJOR 1 +#define LIBHELPER_MINOR 0 +#define LIBHELPER_PATCH 0 + +#include +#include +#include +#include +#include + +#ifndef ONLY_HELPER_MACROS + +enum LogLevels { + INFO = (int)'I', + WARNING = (int)'W', + ERROR = (int)'E', + ABORT = (int)'A' +}; + +constexpr mode_t DEFAULT_FILE_PERMS = 0644; +constexpr mode_t DEFAULT_DIR_PERMS = 0755; +constexpr int YES = 1; +constexpr int NO = 0; + +namespace Helper { + +// Logging +class Logger { +private: + LogLevels _level; + std::ostringstream _oss; + const char *_logFile, *_program_name, *_file; + int _line; + +public: + Logger(LogLevels level, const char* file, const char* name, const char* sfile, int line); + ~Logger(); + + template + Logger& operator<<(const T& msg) + { + _oss << msg; + return *this; + } + Logger& operator<<(std::ostream& (*msg)(std::ostream&)); +}; + +class LoggingProperties { +public: + static std::string_view FILE, NAME; + static bool PRINT; + + static void set(std::string_view name, std::string_view file); + static void setProgramName(std::string_view name); + static void setLogFile(std::string_view file); + static void setPrinting(int state); + static void reset(); +}; + +// Throwable error class +class Error : public std::exception { +private: + std::string _message; + +public: + Error(const char* format, ...); + + const char* what() const noexcept override; +}; + +// Checkers +bool hasSuperUser(); +bool isExists(const std::string_view entry); +bool fileIsExists(const std::string_view file); +bool directoryIsExists(const std::string_view directory); +bool linkIsExists(const std::string_view entry); +bool isLink(const std::string_view entry); +bool isSymbolicLink(const std::string_view entry); +bool isHardLink(const std::string_view entry); +bool areLinked(const std::string_view entry1, const std::string_view entry2); + +// File I/O +bool writeFile(const std::string_view file, const std::string_view text); +std::optional readFile(const std::string_view file); + +// Creators +bool makeDirectory(const std::string_view path); +bool makeRecursiveDirectory(const std::string_view paths); +bool createFile(const std::string_view path); +bool createSymlink(const std::string_view entry1, const std::string_view entry2); + +// Removers +bool eraseEntry(const std::string_view entry); +bool eraseDirectoryRecursive(const std::string_view directory); + +// Getters +size_t fileSize(const std::string_view file); +std::string_view readSymlink(const std::string_view entry); + +// SHA-256 +bool sha256Compare(const std::string_view file1, const std::string_view file2); +std::optional sha256Of(const std::string_view path); + +// Utilities +bool copyFile(const std::string_view file, const std::string_view dest); +bool runCommand(const std::string_view cmd); +bool confirmPropt(const std::string_view message); +std::string currentWorkingDirectory(); +std::string currentDate(); +std::string currentTime(); +std::string runCommandWithOutput(const std::string_view cmd); +std::string pathJoin(std::string base, std::string relative); +std::string pathBasename(const std::string_view entry); +std::string pathDirname(const std::string_view entry); + +// Library-specif +std::string getLibVersion(); + +} // namespace Helper + +#endif // #ifndef ONLY_HELPER_MACROS + +#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) + +#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" + +#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 + +#define LOG(level) Helper::Logger(level, Helper::LoggingProperties::FILE.data(), Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__) + +#endif // #ifndef LIBHELPER_LIB_HPP diff --git a/srclib/libhelper/include/picosha2.h b/srclib/libhelper/include/picosha2.h new file mode 100644 index 0000000..a921736 --- /dev/null +++ b/srclib/libhelper/include/picosha2.h @@ -0,0 +1,377 @@ +/* +The MIT License (MIT) + +Copyright (C) 2017 okdshin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef PICOSHA2_H +#define PICOSHA2_H +// picosha2:20140213 + +#ifndef PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR +#define PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR \ + 1048576 //=1024*1024: default is 1MB memory +#endif + +#include +#include +#include +#include +#include +#include +namespace picosha2 { +typedef unsigned long word_t; +typedef unsigned char byte_t; + +static const size_t k_digest_size = 32; + +namespace detail { +inline byte_t mask_8bit(byte_t x) { return x & 0xff; } + +inline word_t mask_32bit(word_t x) { return x & 0xffffffff; } + +const word_t add_constant[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +const word_t initial_message_digest[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, + 0xa54ff53a, 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19}; + +inline word_t ch(word_t x, word_t y, word_t z) { return (x & y) ^ ((~x) & z); } + +inline word_t maj(word_t x, word_t y, word_t z) { + return (x & y) ^ (x & z) ^ (y & z); +} + +inline word_t rotr(word_t x, std::size_t n) { + assert(n < 32); + return mask_32bit((x >> n) | (x << (32 - n))); +} + +inline word_t bsig0(word_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); } + +inline word_t bsig1(word_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); } + +inline word_t shr(word_t x, std::size_t n) { + assert(n < 32); + return x >> n; +} + +inline word_t ssig0(word_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); } + +inline word_t ssig1(word_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); } + +template +void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) { + assert(first + 64 == last); + static_cast(last); // for avoiding unused-variable warning + word_t w[64]; + std::fill(w, w + 64, word_t(0)); + for (std::size_t i = 0; i < 16; ++i) { + w[i] = (static_cast(mask_8bit(*(first + i * 4))) << 24) | + (static_cast(mask_8bit(*(first + i * 4 + 1))) << 16) | + (static_cast(mask_8bit(*(first + i * 4 + 2))) << 8) | + (static_cast(mask_8bit(*(first + i * 4 + 3)))); + } + for (std::size_t i = 16; i < 64; ++i) { + w[i] = mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) + + w[i - 16]); + } + + word_t a = *message_digest; + word_t b = *(message_digest + 1); + word_t c = *(message_digest + 2); + word_t d = *(message_digest + 3); + word_t e = *(message_digest + 4); + word_t f = *(message_digest + 5); + word_t g = *(message_digest + 6); + word_t h = *(message_digest + 7); + + for (std::size_t i = 0; i < 64; ++i) { + word_t temp1 = h + bsig1(e) + ch(e, f, g) + add_constant[i] + w[i]; + word_t temp2 = bsig0(a) + maj(a, b, c); + h = g; + g = f; + f = e; + e = mask_32bit(d + temp1); + d = c; + c = b; + b = a; + a = mask_32bit(temp1 + temp2); + } + *message_digest += a; + *(message_digest + 1) += b; + *(message_digest + 2) += c; + *(message_digest + 3) += d; + *(message_digest + 4) += e; + *(message_digest + 5) += f; + *(message_digest + 6) += g; + *(message_digest + 7) += h; + for (std::size_t i = 0; i < 8; ++i) { + *(message_digest + i) = mask_32bit(*(message_digest + i)); + } +} + +} // namespace detail + +template +void output_hex(InIter first, InIter last, std::ostream& os) { + os.setf(std::ios::hex, std::ios::basefield); + while (first != last) { + os.width(2); + os.fill('0'); + os << static_cast(*first); + ++first; + } + os.setf(std::ios::dec, std::ios::basefield); +} + +template +void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str) { + std::ostringstream oss; + output_hex(first, last, oss); + hex_str.assign(oss.str()); +} + +template +void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str) { + bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str); +} + +template +std::string bytes_to_hex_string(InIter first, InIter last) { + std::string hex_str; + bytes_to_hex_string(first, last, hex_str); + return hex_str; +} + +template +std::string bytes_to_hex_string(const InContainer& bytes) { + std::string hex_str; + bytes_to_hex_string(bytes, hex_str); + return hex_str; +} + +class hash256_one_by_one { + public: + hash256_one_by_one() { init(); } + + void init() { + buffer_.clear(); + std::fill(data_length_digits_, data_length_digits_ + 4, word_t(0)); + std::copy(detail::initial_message_digest, + detail::initial_message_digest + 8, h_); + } + + template + void process(RaIter first, RaIter last) { + add_to_data_length(static_cast(std::distance(first, last))); + std::copy(first, last, std::back_inserter(buffer_)); + std::size_t i = 0; + for (; i + 64 <= buffer_.size(); i += 64) { + detail::hash256_block(h_, buffer_.begin() + i, + buffer_.begin() + i + 64); + } + buffer_.erase(buffer_.begin(), buffer_.begin() + i); + } + + void finish() { + byte_t temp[64]; + std::fill(temp, temp + 64, byte_t(0)); + std::size_t remains = buffer_.size(); + std::copy(buffer_.begin(), buffer_.end(), temp); + temp[remains] = 0x80; + + if (remains > 55) { + std::fill(temp + remains + 1, temp + 64, byte_t(0)); + detail::hash256_block(h_, temp, temp + 64); + std::fill(temp, temp + 64 - 4, byte_t(0)); + } else { + std::fill(temp + remains + 1, temp + 64 - 4, byte_t(0)); + } + + write_data_bit_length(&(temp[56])); + detail::hash256_block(h_, temp, temp + 64); + } + + template + void get_hash_bytes(OutIter first, OutIter last) const { + for (const word_t* iter = h_; iter != h_ + 8; ++iter) { + for (std::size_t i = 0; i < 4 && first != last; ++i) { + *(first++) = detail::mask_8bit( + static_cast((*iter >> (24 - 8 * i)))); + } + } + } + + private: + void add_to_data_length(word_t n) { + word_t carry = 0; + data_length_digits_[0] += n; + for (std::size_t i = 0; i < 4; ++i) { + data_length_digits_[i] += carry; + if (data_length_digits_[i] >= 65536u) { + carry = data_length_digits_[i] >> 16; + data_length_digits_[i] &= 65535u; + } else { + break; + } + } + } + void write_data_bit_length(byte_t* begin) { + word_t data_bit_length_digits[4]; + std::copy(data_length_digits_, data_length_digits_ + 4, + data_bit_length_digits); + + // convert byte length to bit length (multiply 8 or shift 3 times left) + word_t carry = 0; + for (std::size_t i = 0; i < 4; ++i) { + word_t before_val = data_bit_length_digits[i]; + data_bit_length_digits[i] <<= 3; + data_bit_length_digits[i] |= carry; + data_bit_length_digits[i] &= 65535u; + carry = (before_val >> (16 - 3)) & 65535u; + } + + // write data_bit_length + for (int i = 3; i >= 0; --i) { + (*begin++) = static_cast(data_bit_length_digits[i] >> 8); + (*begin++) = static_cast(data_bit_length_digits[i]); + } + } + std::vector buffer_; + word_t data_length_digits_[4]; // as 64bit integer (16bit x 4 integer) + word_t h_[8]; +}; + +inline void get_hash_hex_string(const hash256_one_by_one& hasher, + std::string& hex_str) { + byte_t hash[k_digest_size]; + hasher.get_hash_bytes(hash, hash + k_digest_size); + return bytes_to_hex_string(hash, hash + k_digest_size, hex_str); +} + +inline std::string get_hash_hex_string(const hash256_one_by_one& hasher) { + std::string hex_str; + get_hash_hex_string(hasher, hex_str); + return hex_str; +} + +namespace impl { +template +void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int, + std::random_access_iterator_tag) { + hash256_one_by_one hasher; + // hasher.init(); + hasher.process(first, last); + hasher.finish(); + hasher.get_hash_bytes(first2, last2); +} + +template +void hash256_impl(InputIter first, InputIter last, OutIter first2, + OutIter last2, int buffer_size, std::input_iterator_tag) { + std::vector buffer(buffer_size); + hash256_one_by_one hasher; + // hasher.init(); + while (first != last) { + int size = buffer_size; + for (int i = 0; i != buffer_size; ++i, ++first) { + if (first == last) { + size = i; + break; + } + buffer[i] = *first; + } + hasher.process(buffer.begin(), buffer.begin() + size); + } + hasher.finish(); + hasher.get_hash_bytes(first2, last2); +} +} + +template +void hash256(InIter first, InIter last, OutIter first2, OutIter last2, + int buffer_size = PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR) { + picosha2::impl::hash256_impl( + first, last, first2, last2, buffer_size, + typename std::iterator_traits::iterator_category()); +} + +template +void hash256(InIter first, InIter last, OutContainer& dst) { + hash256(first, last, dst.begin(), dst.end()); +} + +template +void hash256(const InContainer& src, OutIter first, OutIter last) { + hash256(src.begin(), src.end(), first, last); +} + +template +void hash256(const InContainer& src, OutContainer& dst) { + hash256(src.begin(), src.end(), dst.begin(), dst.end()); +} + +template +void hash256_hex_string(InIter first, InIter last, std::string& hex_str) { + byte_t hashed[k_digest_size]; + hash256(first, last, hashed, hashed + k_digest_size); + std::ostringstream oss; + output_hex(hashed, hashed + k_digest_size, oss); + hex_str.assign(oss.str()); +} + +template +std::string hash256_hex_string(InIter first, InIter last) { + std::string hex_str; + hash256_hex_string(first, last, hex_str); + return hex_str; +} + +inline void hash256_hex_string(const std::string& src, std::string& hex_str) { + hash256_hex_string(src.begin(), src.end(), hex_str); +} + +template +void hash256_hex_string(const InContainer& src, std::string& hex_str) { + hash256_hex_string(src.begin(), src.end(), hex_str); +} + +template +std::string hash256_hex_string(const InContainer& src) { + return hash256_hex_string(src.begin(), src.end()); +} +templatevoid hash256(std::ifstream& f, OutIter first, OutIter last){ + hash256(std::istreambuf_iterator(f), std::istreambuf_iterator(), first,last); + +} +}// namespace picosha2 +#endif // PICOSHA2_H diff --git a/srclib/libhelper/src/Checkers.cpp b/srclib/libhelper/src/Checkers.cpp new file mode 100644 index 0000000..dfababd --- /dev/null +++ b/srclib/libhelper/src/Checkers.cpp @@ -0,0 +1,83 @@ +/* + 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 +#include +#include +#include +#include +#include + +namespace Helper { + +bool hasSuperUser() +{ + return (getuid() == 0); +} + +bool isExists(const std::string_view entry) +{ + struct stat st; + return (stat(entry.data(), &st) == 0); +} + +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) +{ + struct stat st; + if (stat(directory.data(), &st) != 0) return false; + return S_ISDIR(st.st_mode); +} + +bool linkIsExists(const std::string_view entry) +{ + return (isLink(entry) || isHardLink(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) +{ + return isLink(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) +{ + const std::string_view st1 = (isSymbolicLink(entry1)) ? readSymlink(entry1) : entry1; + const std::string_view st2 = (isSymbolicLink(entry2)) ? readSymlink(entry2) : entry2; + + return (st1 == st2); +} + +} // namespace Helper diff --git a/srclib/libhelper/src/Classes.cpp b/srclib/libhelper/src/Classes.cpp new file mode 100644 index 0000000..7793e74 --- /dev/null +++ b/srclib/libhelper/src/Classes.cpp @@ -0,0 +1,96 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include + +namespace Helper { + +std::string_view LoggingProperties::FILE = "last_logs.log", LoggingProperties::NAME = "main"; +bool LoggingProperties::PRINT = NO; + +Error::Error(const char* format, ...) +{ + char buf[1024]; + va_list args; + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + _message = std::string(buf); +} + +const char* Error::what() const noexcept +{ + return _message.data(); +} + +Logger::Logger(LogLevels level, const char* file, const char* name, const char* sfile, int line) : _level(level), _logFile(file), _program_name(name), _file(sfile), _line(line) {} + +Logger::~Logger() +{ + char str[1024]; + snprintf(str, sizeof(str), "<%c> [ %s %s] %s", + (char)_level, + _program_name, + basename((char*)_file), + _line, + currentDate().data(), + currentTime().data(), + _oss.str().data()); + + if (!isExists(_logFile)) createFile(_logFile); + FILE* fp = fopen(_logFile, "a"); + if (fp != NULL) { + fprintf(fp, "%s", str); + fclose(fp); + } + if (LoggingProperties::PRINT) printf("%s\n", str); + + if (_level == ERROR) exit(1); + else if (_level == ABORT) abort(); +} + +Logger& Logger::operator<<(std::ostream& (*msg)(std::ostream&)) +{ + _oss << msg; + return *this; +} + +void LoggingProperties::reset() +{ + FILE = "last_logs.log"; + NAME = "main"; + PRINT = NO; +} + +void LoggingProperties::set(std::string_view file, std::string_view name) +{ + FILE = file; + NAME = name; +} + +void LoggingProperties::setProgramName(std::string_view name) { NAME = name; } +void LoggingProperties::setLogFile(std::string_view file) { FILE = file; } +void LoggingProperties::setPrinting(int state) { PRINT = state; } + + +} // namespace Helper diff --git a/srclib/libhelper/src/FileUtil.cpp b/srclib/libhelper/src/FileUtil.cpp new file mode 100644 index 0000000..6bda2e4 --- /dev/null +++ b/srclib/libhelper/src/FileUtil.cpp @@ -0,0 +1,246 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static FILE* open_file(const std::string_view file, const char* mode) +{ + FILE* fp = fopen(file.data(), mode); + if (fp == nullptr) { + throw Helper::Error("Cannot open %s: %s", file.data(), strerror(errno)); + return fp; + } + + return fp; +} + +namespace Helper { + +bool writeFile(const std::string_view file, const std::string_view text) +{ + FILE* fp = open_file(file, "a"); + if (fp == nullptr) return false; + + fprintf(fp, "%s", text.data()); + fclose(fp); + + return true; +} + +std::optional readFile(const std::string_view file) +{ + FILE* fp = open_file(file, "r"); + if (fp == nullptr) return std::nullopt; + + char buffer[1024]; + std::string str; + while (fgets(buffer, sizeof(buffer), fp)) str += buffer; + + fclose(fp); + return str; +} + +bool copyFile(const std::string_view file, const std::string_view dest) +{ + int src_fd = open(file.data(), O_RDONLY); + if (src_fd == - 1) { + throw Error("Cannot open %s: %s", file.data(), strerror(errno)); + return false; + } + + int dst_fd = open(dest.data(), O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_PERMS); + if (dst_fd == - 1) { + throw Error("Cannot create/open %s: %s", dest.data(), strerror(errno)); + return false; + } + + char buffer[512]; + ssize_t br; + + while ((br = read(src_fd, buffer, 512)) > 0) { + ssize_t bw = write(dst_fd, buffer, br); + if (bw != br) { + throw Error("Cannot write %s: %s", dest.data(), strerror(errno)); + close(src_fd); + close(dst_fd); + return false; + } + } + + close(src_fd); + close(dst_fd); + if (br == -1) { + throw Error("Cannot read %s: %s", file.data(), strerror(errno)); + return false; + } + + return true; +} + +bool makeDirectory(const std::string_view path) +{ + if (isExists(path)) return false; + return (mkdir(path.data(), DEFAULT_DIR_PERMS) == 0) ? true : false; +} + +bool makeRecursiveDirectory(const std::string_view paths) +{ + char tmp[PATH_MAX], *p; + size_t len; + + snprintf(tmp, sizeof(tmp), "%s", paths.data()); + len = strlen(tmp); + if (tmp[len - 1] == '/') tmp[len - 1] = '\0'; + + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (access(tmp, F_OK) != 0) { + if (mkdir(tmp, DEFAULT_DIR_PERMS) != 0 + && errno != EEXIST) { + throw Error("Cannot create directory: %s: %s", tmp, strerror(errno)); + return false; + } + } + *p = '/'; + } + } + + if (access(tmp, F_OK) != 0) { + if (mkdir(tmp, DEFAULT_DIR_PERMS) != 0 && errno != EEXIST) { + throw Error("Cannot create directory: %s: %s", tmp, strerror(errno)); + return false; + } + } + + return true; +} + +bool createFile(const std::string_view path) +{ + if (isExists(path)) { + throw Error("%s: is exists", path.data()); + return false; + } + + int fd = open(path.data(), O_RDONLY | O_CREAT, DEFAULT_FILE_PERMS); + if (fd == -1) { + throw Error("Cannot create %s: %s", path.data(), strerror(errno)); + return false; + } + + close(fd); + return true; +} + +bool createSymlink(const std::string_view entry1, const std::string_view entry2) +{ + int ret = symlink(entry1.data(), entry2.data()); + if (ret != 0) + throw Error("Cannot symlink %s: %s", entry2.data(), strerror(errno)); + + return (ret == 0); +} + +bool eraseEntry(const std::string_view entry) +{ + int ret = remove(entry.data()); + if (ret != 0) + throw Error("Cannot remove %s: %s", entry.data(), strerror(errno)); + + return (ret == 0); +} + +bool eraseDirectoryRecursive(const std::string_view directory) +{ + struct stat buf; + struct dirent *entry; + + DIR *dir = opendir(directory.data()); + if (dir == nullptr) { + throw Error("Cannot open directory %s: %s", directory.data(), strerror(errno)); + return false; + } + + while ((entry = readdir(dir)) != NULL) { + char fullpath[PATH_MAX]; + + if (strcmp(entry->d_name, ".") == 0 + || strcmp(entry->d_name, "..") == 0) + continue; + + snprintf(fullpath, sizeof(fullpath), "%s/%s", directory.data(), entry->d_name); + + if (lstat(fullpath, &buf) == -1) { + throw Error("Cannot stat %s: %s", fullpath, strerror(errno)); + closedir(dir); + return false; + } + + if (S_ISDIR(buf.st_mode)) { + if (!eraseDirectoryRecursive(fullpath)) { + closedir(dir); + return false; + } + } else { + if (unlink(fullpath) == -1) { + throw Error("Cannot unlink %s: %s", fullpath, strerror(errno)); + closedir(dir); + return false; + } + } + } + + closedir(dir); + if (rmdir(directory.data()) == -1) { + throw Error("Cannot remove directory %s: %s", directory.data(), strerror(errno)); + return false; + } + + return true; +} + +std::string_view readSymlink(const std::string_view entry) +{ + char target[PATH_MAX]; + ssize_t len = readlink(entry.data(), target, (sizeof(target) - 1)); + if (len == -1) { + throw Error("Cannot read symlink %s: %s", entry.data(), strerror(errno)); + return entry; + } + + target[len] = '\0'; + return target; +} + +size_t fileSize(const std::string_view file) +{ + struct stat st; + if (stat(file.data(), &st) != 0) return false; + return static_cast(st.st_size); +} + +} // namespace Helper diff --git a/srclib/libhelper/src/Sha256.cpp b/srclib/libhelper/src/Sha256.cpp new file mode 100644 index 0000000..a5badb9 --- /dev/null +++ b/srclib/libhelper/src/Sha256.cpp @@ -0,0 +1,54 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include + +namespace Helper { + +std::optional sha256Of(const std::string_view path) +{ + if (!fileIsExists(path)) { + throw Error("Is not exists or not file: %s", path.data()); + return std::nullopt; + } + + std::ifstream file(path, std::ios::binary); + if (!file) { + throw Error("Cannot open file: %s", path.data()); + return std::nullopt; + } + + std::vector hash(picosha2::k_digest_size); + picosha2::hash256(path, hash.begin(), hash.end()); + return picosha2::bytes_to_hex_string(hash.begin(), hash.end()); +} + +bool sha256Compare(const std::string_view file1, const std::string_view file2) +{ + auto f1 = sha256Of(file1); + auto f2 = sha256Of(file2); + if (f1->empty() || f2->empty()) return false; + return (*f1 == *f2); +} + +} // namespace Helper diff --git a/srclib/libhelper/src/Utilities.cpp b/srclib/libhelper/src/Utilities.cpp new file mode 100644 index 0000000..f274d73 --- /dev/null +++ b/srclib/libhelper/src/Utilities.cpp @@ -0,0 +1,140 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Helper { + +bool runCommand(const std::string_view cmd) +{ + return (system(cmd.data()) == 0) ? true : false; +} + +bool confirmPropt(const std::string_view message) +{ + char p; + + printf("%s [ y / n ]: ", message.data()); + std::cin >> p; + + if (p == 'y' || p == 'Y') return true; + else if (p == 'n' || p == 'N') return false; + else { + printf("Unexpected answer: '%c'. Try again.\n", p); + return confirmPropt(message); + } + + return false; +} + +std::string currentWorkingDirectory() +{ + char cwd[1024]; + if (getcwd(cwd, sizeof(cwd)) == nullptr) return std::string(); + return cwd; +} + +std::string currentDate() +{ + time_t t = time(nullptr); + struct tm *date = localtime(&t); + + if (date) + return std::string( + std::to_string(date->tm_mday) + "/" + + std::to_string(date->tm_mon + 1) + "/" + + std::to_string(date->tm_year + 1900)); + return "--/--/----"; +} + +std::string currentTime() +{ + time_t t = time(nullptr); + struct tm *date = localtime(&t); + + if (date) + return std::string( + std::to_string(date->tm_hour) + ":" + + std::to_string(date->tm_min) + ":" + + std::to_string(date->tm_sec)); + return "--:--:--"; +} + +std::string runCommandWithOutput(const std::string_view cmd) +{ + std::unique_ptr pipe(popen(cmd.data(), "r"), pclose); + if (!pipe) { + throw Error("Cannot run command: %s", cmd.data()); + return {}; + } + + std::string end; + char buffer[1024]; + + while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) end += buffer; + + return end; +} + +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) +{ + if (!isExists(entry)) { + throw Error("No such file or directory: %s", entry.data()); + return {}; + } + + char* base = basename((char*)entry.data()); + return (base == nullptr) ? std::string() : std::string(base); +} + +std::string pathDirname(const std::string_view entry) +{ + if (!isExists(entry)) { + throw Error("No such file or directory: %s", entry.data()); + return {}; + } + + char* base = dirname((char*)entry.data()); + return (base == nullptr) ? std::string() : std::string(base); +} + +std::string getLibVersion() +{ + return std::string( + std::to_string(LIBHELPER_MAJOR) + "." + + std::to_string(LIBHELPER_MINOR) + "." + + std::to_string(LIBHELPER_PATCH) + ); +} + +} // namespace Helper diff --git a/srclib/libhelper/tests/test.cpp b/srclib/libhelper/tests/test.cpp new file mode 100644 index 0000000..b71a73a --- /dev/null +++ b/srclib/libhelper/tests/test.cpp @@ -0,0 +1,101 @@ +/* + Copyright 2025 Yağız Zengin + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#define PROGRAM_NAME "helper_test" + +#include +#include + +char* TEST_DIR = nullptr; + +std::string test_path(const char* file) +{ + std::string end = std::string(TEST_DIR) + "/" + file; + return end; +} + +int main(int argc, char** argv) +{ + if (argc < 2) return 2; + else TEST_DIR = argv[1]; + + try { + std::cout << "Has super user?; " << std::boolalpha << Helper::hasSuperUser() << std::endl; + std::cout << "file.txt is exists?; " << std::boolalpha << Helper::isExists(test_path("file.txt")) << std::endl; + std::cout << "'file.txt' file is exists?; " << std::boolalpha << Helper::fileIsExists(test_path("file")) << std::endl; + std::cout << "'dir' directory is exists?; " << std::boolalpha << Helper::directoryIsExists(test_path("dir")) << std::endl; + std::cout << "'linkdir' is link?; " << std::boolalpha << Helper::isLink(test_path("linkdir")) << std::endl; + std::cout << "'linkdir' is symlink?; " << std::boolalpha << Helper::isSymbolicLink(test_path("linkdir")) << std::endl; + std::cout << "'linkdir' is hardlink?; " << std::boolalpha << Helper::isHardLink(test_path("linkdir")) << std::endl; + std::cout << "'linkdir' is symlink to 'dir'?; " << std::boolalpha << Helper::areLinked(test_path("linkdir"), test_path("dir")) << std::endl; + + if (!Helper::writeFile("file.txt", "hello world")) + throw Helper::Error("Cannor write \"hello world\" in 'file.txt'"); + else + std::cout << "file.txt writed." << std::endl; + + auto content = Helper::readFile("file.txt"); + if (!content) + throw Helper::Error("Cannot read 'file.txt'"); + else + std::cout << "'file.txt': " << *content << std::endl; + + std::cout << "Making directory 'dir2': " << std::boolalpha << Helper::makeDirectory(test_path("dir2")) << std::endl; + std::cout << "Making recursive directories 'dir3/x/y': " << std::boolalpha << Helper::makeRecursiveDirectory(test_path("dir3/x/y")) << std::endl; + std::cout << "Create 'file2.txt': " << std::boolalpha << Helper::createFile(test_path("file2.txt")) << std::endl; + std::cout << "Create symlink 'file2.txt' to 'file2lnk.txt': " << std::boolalpha << Helper::createSymlink(test_path("file2.txt"), test_path("file2lnk.txt")) << std::endl; + std::cout << "Size of 'file2.txt': " << Helper::fileSize(test_path("file2.txt")) << std::endl; + std::cout << "Erasing 'file.txt': " << std::boolalpha << Helper::eraseEntry(test_path("file.txt")) << std::endl; + std::cout << "Erasing 'dir2': " << std::boolalpha << Helper::eraseEntry(test_path("dir2")) << std::endl; + std::cout << "Read link of 'file2lnk.txt': " << Helper::readSymlink(test_path("file2lnk.txt")) << std::endl; + + auto sha256 = Helper::sha256Of(test_path("file2.txt")); + if (!sha256) + throw Helper::Error("Cannot get sha256 of 'file2.txt'"); + else + std::cout << "SHA256 of 'file2.txt': " << *sha256 << std::endl; + + std::cout << "'file2.txt' and 'file2lnk.txt' same? (SHA256): " << std::boolalpha << Helper::sha256Compare(test_path("file2.txt"), test_path("file2lnk.txt")) << std::endl; + std::cout << "Copy 'file2.txt' as 'file2cpy.txt': " << std::boolalpha << Helper::copyFile(test_path("file2.txt"), test_path("file2cpy.txt")) << std::endl; + std::cout << "Run command: 'ls': " << std::boolalpha << Helper::runCommand("ls") << std::endl; + std::cout << "Spawn confirm propt..." << std::endl; + + bool p = Helper::confirmPropt("Please answer"); + std::cout << "Result of confirm propt: " << std::boolalpha << p << std::endl; + + std::cout << "Working directory: " << Helper::currentWorkingDirectory() << std::endl; + std::cout << "Current date: " << Helper::currentDate() << std::endl; + std::cout << "Current time: " << Helper::currentTime() << std::endl; + std::cout << "Output of 'ls' command: " << Helper::runCommandWithOutput("ls") << std::endl; + std::cout << "Basename of " << test_path("file2.txt") << ": " << Helper::pathBasename(test_path("file2.txt")) << std::endl; + std::cout << "Dirname of " << test_path("file2.txt") << ": " << Helper::pathDirname(test_path("file2.txt")) << std::endl; + + std::cout << "pathJoin() test 1: " << Helper::pathJoin("mydir", "dir2") << std::endl; + std::cout << "pathJoin() test 2: " << Helper::pathJoin("mydir/", "dir2") << std::endl; + std::cout << "pathJoin() test 3: " << Helper::pathJoin("mydir/", "/dir2") << std::endl; + std::cout << "pathJoin() test 4: " << Helper::pathJoin("mydir", "/dir2") << std::endl; + + LOG(INFO) << "Info message" << std::endl; + LOG(WARNING) << "Warning message" << std::endl; + LOG(ERROR) << "Error message" << std::endl; + LOG(ABORT) << "Abort message" << std::endl; + } catch (Helper::Error& err) { + std::cout << err.what() << std::endl; + return 1; + } + + return 0; +} diff --git a/srclib/libhelper/tests/test.sh b/srclib/libhelper/tests/test.sh new file mode 100644 index 0000000..1e0098d --- /dev/null +++ b/srclib/libhelper/tests/test.sh @@ -0,0 +1,23 @@ +#!/usr/bin/bash +# +# Copyright 2025 Yağız Zengin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -e + +if [ -z $1 ]; then echo "$0: Provide test path!"; exit 1; fi +if [ ! -d "$1/dir" ]; then mkdir $1/dir; fi +touch "$1/file.txt" +ln -s $1/dir $1/linkdir &>/dev/null diff --git a/srclib/libpartition_map/CMakeLists.txt b/srclib/libpartition_map/CMakeLists.txt new file mode 100644 index 0000000..d2cf665 --- /dev/null +++ b/srclib/libpartition_map/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# 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. +# + +# Sources +set(LIBPARTITION_MAP_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/Getters.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/PartitionMap.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Type.cpp +) +set(LIBPARTITION_MAP_FLAGS -Wall -Werror -DLOG_FILE="/storage/emulated/0/.last_pmt.log" -DPROGRAM_NAME="libpartition_map") + +# Add targets +add_library(partition_map_shared SHARED ${LIBPARTITION_MAP_SOURCES}) +add_library(partition_map_static STATIC ${LIBPARTITION_MAP_SOURCES}) +add_executable(libpartition_map_test tests/test.cpp) + +# Set appropriate output names +set_target_properties(partition_map_shared PROPERTIES OUTPUT_NAME "partition_map") +set_target_properties(partition_map_static PROPERTIES OUTPUT_NAME "partition_map") + +# Set compiler flags +target_compile_options(partition_map_shared PRIVATE ${LIBPARTITION_MAP_FLAGS}) +target_compile_options(partition_map_static PRIVATE ${LIBPARTITION_MAP_FLAGS}) +target_compile_options(libpartition_map_test PRIVATE ${LIBPARTITION_MAP_FLAGS}) +target_link_options(libpartition_map_test PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") +target_link_options(partition_map_shared PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") +target_link_libraries(libpartition_map_test PRIVATE partition_map_shared PRIVATE helper_shared) +target_link_libraries(partition_map_shared PRIVATE helper_shared) diff --git a/srclib/libpartition_map/include/libpartition_map/lib.hpp b/srclib/libpartition_map/include/libpartition_map/lib.hpp new file mode 100644 index 0000000..0dc3d74 --- /dev/null +++ b/srclib/libpartition_map/include/libpartition_map/lib.hpp @@ -0,0 +1,332 @@ +/* + 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. +*/ + +#ifndef LIBPARTITION_MAP_LIB_HPP +#define LIBPARTITION_MAP_LIB_HPP + +#define LIBPARTITION_MAP_MAJOR 1 +#define LIBPARTITION_MAP_MINOR 0 +#define LIBPARTITION_MAP_PATCH 0 + +#include +#include +#include +#include +#include +#include +#include // for std::pair +#include // for uint64_t +#include + +namespace PartitionMap { + +struct _entry { + std::string name; + + struct { + uint64_t size; + bool isLogical; + } props; +}; + +class basic_partition_map { +private: + void _resize_map(); + int _index_of(const std::string_view name) const; + +public: + _entry* _data; + size_t _count, _capacity; + + struct _returnable_entry { + uint64_t size; + bool isLogical; + }; + + 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); + uint64_t get_size(const std::string_view name) const; + bool is_logical(const std::string_view name) const; + _returnable_entry get_all(const std::string_view name) const; + bool find(const std::string_view name) const; + std::string find_(const std::string name) const; + size_t size() const; + 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; + + iterator(_entry* p); + + auto operator*() -> std::pair; + _entry* operator->(); + iterator& operator++(); + iterator operator++(int); + bool operator!=(const iterator& other) const; + bool operator==(const iterator& other) const; + }; + + class constant_iterator { + public: + const _entry* ptr; + + constant_iterator(const _entry* p); + + auto operator*() const -> std::pair; + 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 */ + iterator begin(); + iterator end(); + + constant_iterator begin() const; + constant_iterator cbegin() const; + constant_iterator end() const; + constant_iterator cend() const; +}; + +using Map_t = basic_partition_map; + +class basic_partition_map_builder { +private: + Map_t _current_map; + std::string _workdir; + bool _any_generating_error, _map_builded; + + bool _is_real_block_dir(const std::string_view path) const; + Map_t _build_map(std::string_view path, bool logical = false); + void _insert_logicals(Map_t&& logicals); + void _map_build_check() const; + uint64_t _get_size(const std::string path); + +public: + /** + * Default constructor + * ------------------- + * By default, it searches the directories in the + * defaultEntryList in PartitionMap.cpp in order and + * uses the directory it finds. + */ + basic_partition_map_builder(); + + /** + * Secondary constructor + * --------------------- + * It has two arguments: + * - Directory path to search + */ + basic_partition_map_builder(const std::string_view path); + + /** + * getAll() + * ------ + * WARNING: Learn about std::optional before using this function. + * + * Returns the current list content in Map_t type. + * If no list is created, returns std::nullopt. + */ + Map_t getAll() const; + + /** + * get(name) + * --------- + * WARNING: Learn about std::optional before using this function. + * + * Returns information of a specific partition in + * Map_temp_t type. If the partition is not in the + * currently created list, returns std::nullopt. + */ + std::optional> get(const std::string_view name) const; + + /** + * getLogicalPartitionList() + * ------------------------- + * WARNING: Learn about std::optional before using this function. + * + * If there is a logical partition(s) in the created + * 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. + */ + std::optional> getLogicalPartitionList() const; + + /** + * getPhysicalPartitionList() + * -------------------------- + * WARNING: Learn about std::optional before using this function. + * + * 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. + */ + std::optional> getPhysicalPartitionList() const; + + /** + * getRealLinkPathOf(name) + * ----------------------- + * WARNING: Learn about std::optional before using this function. + * + * 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. + */ + std::string getRealLinkPathOf(const std::string_view name) const; + + /** + * getRealPathOf(name) + * ------------------- + * WARNING: Learn about std::optional before using this function. + * + * Returns the actual path of the partition as + * std::string. Like /dev/block/sda5 + */ + std::string getRealPathOf(const std::string_view name) const; + + /** + * getCurrentWorkDir() + * ------------------- + * WARNING: Learn about std::optional before using this function. + * + * If it exists, the path to the search string is + * returned as std::string. If it does not exist, + * an empty std::string is returned. + */ + std::string getCurrentWorkDir() const; + + /** + * hasPartition(name) + * ------------------ + * Returns whether the entered partition name is in the + * created partition list as a bool. + */ + bool hasPartition(const std::string_view name) const; + + /** + * isLogical(name) + * --------------- + * Returns the bool type status of whether the + * entered section name is marked as logical in the + * created list. Alternatively, the current section + * information can be retrieved with the Get() function + * and checked for logicality. + */ + bool isLogical(const std::string_view name) const; + + /** + * clear() + * ------- + * The created list and the current search index name are cleared. + */ + void clear(); + + /** + * readDirectory(path) + * ------------------- + * 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(const std::string_view path); + + /** + * empty() + * ------- + * 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. + */ + bool empty() const; + + /** + * sizeOf(name) + * ------------ + * WARNING: Learn about std::optional before using this function. + * + * 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. + */ + uint64_t sizeOf(const std::string_view name) const; + + /** + * == operator + * ----------- + * 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==(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs); + + /** + * != operator + * ----------- + * The opposite logic of the == operator. + */ + friend bool operator!=(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs); + + /** + * Boolean operator + * ---------------- + * You can check whether the object was created + * successfully. If the problem did not occur, true is + * returned, if it did, false is returned. + */ + operator bool() const; + + /** + * ! operator + * ---------- + * Returns true if the object creation failed (i.e., there's a problem), + * and false if the object is correctly created. + */ + bool operator!() const; +}; + +using Error = Helper::Error; + +/** + * getLibVersion() + * --------------- + * 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; + +} // namespace PartitionMap + +#endif // #ifndef LIBPARTITION_MAP_LIB_HPP diff --git a/srclib/libpartition_map/src/Getters.cpp b/srclib/libpartition_map/src/Getters.cpp new file mode 100644 index 0000000..0e6fc1f --- /dev/null +++ b/srclib/libpartition_map/src/Getters.cpp @@ -0,0 +1,87 @@ +/* + 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 +#include +#include +#include + +namespace PartitionMap { + +Map_t basic_partition_map_builder::getAll() const +{ + _map_build_check(); + return _current_map; +} + +std::optional> 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> basic_partition_map_builder::getLogicalPartitionList() const +{ + _map_build_check(); + + std::list logicals; + for (const auto& [name, props] : _current_map) + if (props.isLogical) logicals.push_back(name); + + if (logicals.empty()) return std::nullopt; + return logicals; +} + +std::optional> basic_partition_map_builder::getPhysicalPartitionList() const +{ + _map_build_check(); + + std::list physicals; + for (const auto& [name, props] : _current_map) + if (!props.isLogical) physicals.push_back(name); + + if (physicals.empty()) return std::nullopt; + return physicals; +} + +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 +{ + _map_build_check(); + + std::string full = _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; +} + +} // namespace PartitionMap diff --git a/srclib/libpartition_map/src/PartitionMap.cpp b/srclib/libpartition_map/src/PartitionMap.cpp new file mode 100644 index 0000000..66838d1 --- /dev/null +++ b/srclib/libpartition_map/src/PartitionMap.cpp @@ -0,0 +1,209 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static constexpr std::array defaultEntryList = { + "/dev/block/by-name", + "/dev/block/bootdevice/by-name", + "/dev/block/platform/bootdevice/by-name" +}; + +namespace PartitionMap { + +bool basic_partition_map_builder::_is_real_block_dir(const std::string_view path) const +{ + if (path.find("/block/") == std::string::npos) return false; + return true; +} + +Map_t basic_partition_map_builder::_build_map(std::string_view path, bool logical) +{ + Map_t map; + std::vector 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(); + }); + + 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); + } + + return map; +} + +void basic_partition_map_builder::_insert_logicals(Map_t&& logicals) +{ + _current_map.merge(logicals); +} + +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) +{ + std::string real = std::filesystem::read_symlink(path); + int fd = open(real.data(), O_RDONLY); + if (fd < 0) + throw Error("Cannot open %s: %s", real.data(), strerror(errno)); + + uint64_t size = 0; + if (ioctl(fd, BLKGETSIZE64, &size) != 0) { + close(fd); + throw Error("ioctl() process failed for %s: %s", real.data(), strerror(errno)); + } + + close(fd); + return size; +} + +basic_partition_map_builder::basic_partition_map_builder() +{ + for (const auto& path : defaultEntryList) { + if (std::filesystem::exists(path)) { + _current_map = _build_map(path); + if (_current_map.empty()) { + _any_generating_error = true; + continue; + } else { + _workdir = path; + break; + } + } + } + + if (_current_map.empty()) + throw Error("Cannot build map by any default search entry."); + + _insert_logicals(_build_map("/dev/block/mapper", true)); + _map_builded = true; +} + +basic_partition_map_builder::basic_partition_map_builder(const std::string_view path) +{ + if (std::filesystem::exists(path)) { + _is_real_block_dir(path); + _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()); + + _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; + + 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()); + + _insert_logicals(_build_map("/dev/block/mapper", true)); + _map_builded = true; + return true; +} + +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 +{ + _map_build_check(); + return _current_map.get_size(name); +} + +bool operator==(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs) +{ + return lhs._current_map == rhs._current_map; +} + +bool operator!=(basic_partition_map_builder& lhs, basic_partition_map_builder& rhs) +{ + return !(lhs == rhs); +} + +basic_partition_map_builder::operator bool() const +{ + return !this->_any_generating_error; +} + +bool basic_partition_map_builder::operator!() const +{ + return this->_any_generating_error; +} + +std::string getLibVersion() +{ + return std::string( + std::to_string(LIBPARTITION_MAP_MAJOR) + "." + + std::to_string(LIBPARTITION_MAP_MINOR) + "." + + std::to_string(LIBPARTITION_MAP_PATCH) + ); +} + +} // namespace PartitionMap diff --git a/srclib/libpartition_map/src/Type.cpp b/srclib/libpartition_map/src/Type.cpp new file mode 100644 index 0000000..3494b24 --- /dev/null +++ b/srclib/libpartition_map/src/Type.cpp @@ -0,0 +1,278 @@ +/* + 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 +#include +#include +#include + +namespace PartitionMap { + +basic_partition_map::iterator::iterator(_entry* p) : ptr(p) {} + +auto basic_partition_map::iterator::operator*() -> std::pair +{ + return {ptr->name, ptr->props}; +} + +_entry* basic_partition_map::iterator::operator->() +{ + return ptr; +} + +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 tmp = *this; + ++ptr; + return tmp; +} + +bool basic_partition_map::iterator::operator==(const basic_partition_map::iterator& other) const +{ + return ptr == other.ptr; +} + +bool basic_partition_map::iterator::operator!=(const basic_partition_map::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 { + 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) +{ + basic_partition_map::constant_iterator tmp = *this; + ++ptr; + return tmp; +} + +bool basic_partition_map::constant_iterator::operator==(const basic_partition_map::constant_iterator& other) const +{ + return ptr == other.ptr; +} + +bool basic_partition_map::constant_iterator::operator!=(const basic_partition_map::constant_iterator& other) const +{ + return ptr != other.ptr; +} + +void basic_partition_map::_resize_map() +{ + size_t new_capacity = _capacity * 2; + _entry* 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 (int)i; + } + + return 0; +} + +basic_partition_map::basic_partition_map(const std::string name, uint64_t size, 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() : _count(0), _capacity(6) +{ + _data = new _entry[_capacity]; +} + +basic_partition_map::~basic_partition_map() +{ + delete[] _data; +} + +bool basic_partition_map::insert(const std::string name, uint64_t size, bool logical) +{ + if (name == _data[_index_of(name)].name) return false; + if (_count == _capacity) _resize_map(); + + _data[_count++] = {name, {size, logical}}; + return true; +} + +void basic_partition_map::merge(const basic_partition_map& map) +{ + for (const auto& [name, props] : map) + insert(name, props.size, props.isLogical); +} + +uint64_t basic_partition_map::get_size(const std::string_view name) const +{ + int pos = _index_of(name); + if (name == _data[pos].name) return _data[pos].props.size; + + return 0; +} + +bool basic_partition_map::is_logical(const std::string_view name) const +{ + int pos = _index_of(name); + if (name == _data[pos].name) return _data[pos].props.isLogical; + + return false; +} + +basic_partition_map::_returnable_entry basic_partition_map::get_all(const std::string_view name) const +{ + int pos = _index_of(name); + if (name == _data[pos].name) + 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() +{ + 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; + + 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; + + return true; +} + +bool basic_partition_map::operator!=(const basic_partition_map& other) const +{ + return !(*this == other); +} + +basic_partition_map::iterator basic_partition_map::begin() +{ + return basic_partition_map::iterator(_data); +} + +basic_partition_map::iterator basic_partition_map::end() +{ + return basic_partition_map::iterator(_data + _count); +} + +basic_partition_map::constant_iterator basic_partition_map::begin() const +{ + return basic_partition_map::constant_iterator(_data); +} + +basic_partition_map::constant_iterator basic_partition_map::cbegin() const +{ + return basic_partition_map::constant_iterator(_data); +} + +basic_partition_map::constant_iterator basic_partition_map::end() const +{ + return basic_partition_map::constant_iterator(_data + _count); +} + +basic_partition_map::constant_iterator basic_partition_map::cend() const +{ + return basic_partition_map::constant_iterator(_data + _count); +} + +} // namespace PartitionMap diff --git a/srclib/libpartition_map/tests/test.cpp b/srclib/libpartition_map/tests/test.cpp new file mode 100644 index 0000000..9cf436a --- /dev/null +++ b/srclib/libpartition_map/tests/test.cpp @@ -0,0 +1,78 @@ +/* + 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 +#include +#include + +int main(void) { + if (getuid() != 0) return 2; + + try { + PartitionMap::BuildMap MyMap; + if (!MyMap) { + MyMap.readDirectory("/dev/block/by-name"); + if (!MyMap) throw PartitionMap::Error("Cannot generate object!"); + } + + auto map = MyMap.getAll(); + if (map.empty()) throw PartitionMap::Error("getAll() empty"); + for (const auto& [name, props] : map) { + std::cout << "Partition: " << name << ", size: " + << props.size << ", logical: " + << props.isLogical << std::endl; + } + + auto boot = MyMap.get("boot"); + if (!boot) throw PartitionMap::Error("get(\"boot\") returned nullopt"); + std::cout << "Name: boot" << ", size: " + << boot->first << ", logical: " + << boot->second << std::endl; + + auto logicals = MyMap.getLogicalPartitionList(); + if (!logicals) throw PartitionMap::Error("getLogicalPartitionList() returned nullopt"); + std::cout << "Logical partitions: " << std::endl; + for (const auto& name : *logicals) + std::cout << " - " << name << std::endl; + + auto physicals = MyMap.getPhysicalPartitionList(); + if (!physicals) throw PartitionMap::Error("getPhysicalPartitionList() returned nullopt"); + std::cout << "Physical partitions: " << std::endl; + for (const auto& name : *physicals) + std::cout << " - " << name << std::endl; + + std::cout << "Boot: " << MyMap.getRealLinkPathOf("boot") << std::endl; + std::cout << "Boot (realpath): " << MyMap.getRealPathOf("boot") << std::endl; + std::cout << "Search dir: " << MyMap.getCurrentWorkDir() << std::endl; + std::cout << "Has partition cache? = " << MyMap.hasPartition("cache") << std::endl; + std::cout << "system partition is logical? = " << MyMap.isLogical("system") << std::endl; + std::cout << "Size of system partition: " << MyMap.sizeOf("system") << std::endl; + + MyMap.clear(); + if (!MyMap.empty()) throw PartitionMap::Error("map cleaned but check fail"); + + MyMap.readDirectory("/dev/block/by-name"); + PartitionMap::BuildMap MyMap2; + + if (MyMap == MyMap2) std::cout << "map1 = map2" << std::endl; + if (MyMap != MyMap2) std::cout << "map1 != map2" << std::endl; + } catch (PartitionMap::Error& error) { + std::cerr << error.what() << std::endl; + return 1; + } + + return 0; +} diff --git a/tests/test.cpp b/tests/test.cpp new file mode 100644 index 0000000..e69de29