Compare commits
77 Commits
20250811
...
798cad275c
| Author | SHA1 | Date | |
|---|---|---|---|
| 798cad275c | |||
| 066080c999 | |||
| 397b95466d | |||
| 0ff94cc4b9 | |||
| b60c5c023f | |||
| 17f2fb5660 | |||
| 6e8931bd68 | |||
| 7aca7792ae | |||
| 318739adc8 | |||
| 398b119cb4 | |||
| b99f20c6a1 | |||
| 37dc3ac94b | |||
| 83c56c795e | |||
| de1cb5dd5a | |||
| 9625bf6df0 | |||
| 77760bd1d4 | |||
| 1984825dec | |||
| ab35740fb6 | |||
| 08e51c4a15 | |||
| 063d62fd85 | |||
| 2615ddd127 | |||
| 51ae72aba1 | |||
| deab481fd7 | |||
| e1dc7132ee | |||
| 360959381b | |||
| 0832b57828 | |||
| e7baf4f5bc | |||
| fea9c834fc | |||
| 025ccf3acb | |||
| d19343d644 | |||
| 1a9b4ff5ad | |||
| d7bd11165d | |||
| c2a41b6365 | |||
| bfd3324558 | |||
| 41336609fa | |||
| e0f0b5b484 | |||
| 631c735a9a | |||
| 80bcc0268d | |||
| 853d2c97b3 | |||
| 753d9d8ad2 | |||
| 1d1d6e98ce | |||
| 705f529f55 | |||
| 249b44a81a | |||
| 62b1ff98d9 | |||
| 7b29059a8e | |||
| 9724bee46e | |||
| 366bb28612 | |||
| 58330fddf4 | |||
| 62b73ac91a | |||
| 20ad64c8c5 | |||
| 6999975f6a | |||
| 54f2a48ffa | |||
| 9391847534 | |||
| bfd5a78863 | |||
| d4703df1a5 | |||
| c3a5e97d41 | |||
| 47382ebf1c | |||
| 7240cca537 | |||
| 6a8fd5854d | |||
| f3732ff158 | |||
| b7f5348b89 | |||
| 235402ed23 | |||
| e17ac42e55 | |||
| 1bc3b5ccef | |||
| c3acd4b370 | |||
| 05f173e895 | |||
| 638ed3017e | |||
| 563e8a583e | |||
| bf0df8cc83 | |||
| 0bc5f70294 | |||
| d74f385a68 | |||
| 23087966d6 | |||
| 7350791d04 | |||
| 5d06c804e3 | |||
| 442155b9f6 | |||
| a1211c91fe | |||
| f33433cfe6 |
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
sudo apt install make cmake extra-cmake-modules zip -y
|
||||
sudo apt install make ninja-build cmake extra-cmake-modules zip -y
|
||||
|
||||
- name: Setup Android NDK
|
||||
id: setup-ndk
|
||||
@@ -49,6 +49,9 @@ jobs:
|
||||
zip pmt-static-armeabi-v7a.zip pmt_static
|
||||
echo "BUILD_DATE=$(date +%Y%m%d)" >> $GITHUB_ENV
|
||||
echo "BUILD=${{ github.workspace }}/pmt" >> $GITHUB_ENV
|
||||
cd ..
|
||||
echo -e "Read [Wiki - About Release Types](https://github.com/ShawkTeam/pmt-renovated/wiki/About-Release-Types) for getting more information.\n\n### Changes\n" > release.txt
|
||||
git log --since="2025-08-21" --pretty=format:" * %ad | [%s](https://github.com/ShawkTeam/pmt-renovated/commit/%H)" --date=short | sed 's/ -.*//' | grep -v cleanup >> release.txt
|
||||
working-directory: ${{ github.workspace }}
|
||||
|
||||
- name: Upload To GitHub Releases
|
||||
@@ -60,4 +63,4 @@ jobs:
|
||||
${{ env.BUILD }}/build_armeabi-v7a/*.zip
|
||||
name: Partition Manager Tool Release ${{ env.BUILD_DATE }}
|
||||
tag_name: ${{ env.BUILD_DATE }}
|
||||
body: "Read [RELEASE-TYPES.md](https://github.com/ShawkTeam/pmt-renovated/blob/main/RELEASE-TYPES.md) for getting more information."
|
||||
body_path: ${{ env.BUILD }}/release.txt
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,8 +7,7 @@ cmake-build-*
|
||||
include/generated
|
||||
|
||||
# Dont't add build directories
|
||||
build_arm64-v8a
|
||||
build_armeabi-v7a
|
||||
build_*
|
||||
|
||||
# Don't add generated objects and libs
|
||||
*.o
|
||||
|
||||
6
.idea/editor.xml
generated
6
.idea/editor.xml
generated
@@ -117,6 +117,7 @@
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppModulePartitionWithSeveralPartitionUnits/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
@@ -243,7 +244,7 @@
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
|
||||
@@ -263,13 +264,12 @@
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Tab" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
|
||||
110
Android.bp
Normal file
110
Android.bp
Normal file
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
// Partition manager tool source list
|
||||
filegroup {
|
||||
name: "pmt_srcs",
|
||||
srcs: [
|
||||
"src/FunctionManager.cpp",
|
||||
"src/Main.cpp",
|
||||
"src/PartitionManager.cpp",
|
||||
"src/functions/BackupFunction.cpp",
|
||||
"src/functions/EraseFunction.cpp",
|
||||
"src/functions/FlashFunction.cpp",
|
||||
"src/functions/InfoFunction.cpp",
|
||||
"src/functions/MemoryTestFunction.cpp",
|
||||
"src/functions/PartitionSizeFunction.cpp",
|
||||
"src/functions/RealPathFunction.cpp",
|
||||
"src/functions/RebootFunction.cpp",
|
||||
"src/functions/TypeFunction.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
// libhelper source list
|
||||
filegroup {
|
||||
name: "libhelper_srcs",
|
||||
srcs: [
|
||||
"srclib/libhelper/src/Checkers.cpp",
|
||||
"srclib/libhelper/src/Classes.cpp",
|
||||
"srclib/libhelper/src/FileUtil.cpp",
|
||||
"srclib/libhelper/src/Sha256.cpp",
|
||||
"srclib/libhelper/src/Utilities.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
// libpartition_map source list
|
||||
filegroup {
|
||||
name: "libpartition_map_srcs",
|
||||
srcs: [
|
||||
"srclib/libpartition_map/src/Getters.cpp",
|
||||
"srclib/libpartition_map/src/Magic.cpp",
|
||||
"srclib/libpartition_map/src/PartitionMap.cpp",
|
||||
"srclib/libpartition_map/src/Type.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
// Default configurations of pmt
|
||||
cc_defaults {
|
||||
name: "pmt_defaults",
|
||||
recovery_available: true,
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Os",
|
||||
"-fexceptions",
|
||||
"-DANDROID_BUILD",
|
||||
],
|
||||
ldflags: ["-Wl,-s"],
|
||||
local_include_dirs: [
|
||||
"include",
|
||||
"srclib/libhelper/include",
|
||||
"srclib/libpartition_map/include",
|
||||
],
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
"srclib/libhelper/include",
|
||||
"srclib/libpartition_map/include",
|
||||
],
|
||||
shared_libs: ["libbase"],
|
||||
}
|
||||
|
||||
// libhelper library target
|
||||
cc_library_shared {
|
||||
name: "libhelper",
|
||||
defaults: ["pmt_defaults"],
|
||||
srcs: [":libhelper_srcs"],
|
||||
}
|
||||
|
||||
// libpartition_map library target
|
||||
cc_library_shared {
|
||||
name: "libpartition_map",
|
||||
defaults: ["pmt_defaults"],
|
||||
srcs: [":libpartition_map_srcs"],
|
||||
shared_libs: ["libhelper"],
|
||||
static_libs: ["libc++fs"],
|
||||
}
|
||||
|
||||
// pmt executable target
|
||||
cc_binary {
|
||||
name: "pmt",
|
||||
defaults: ["pmt_defaults"],
|
||||
srcs: [":pmt_srcs"],
|
||||
shared_libs: [
|
||||
"libhelper",
|
||||
"libpartition_map",
|
||||
],
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
# Project info
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(pmt VERSION 1.0.0)
|
||||
project(pmt VERSION 1.3.0)
|
||||
|
||||
# Set compiler flags
|
||||
add_compile_options(-Wall -Werror -Wno-deprecated-declarations)
|
||||
@@ -29,7 +29,7 @@ else()
|
||||
endif()
|
||||
|
||||
# Add pmt's CMake module(s)
|
||||
include(cmake/generate_headers.cmake)
|
||||
include(build/cmake/generate_headers.cmake)
|
||||
|
||||
# Generate header(s)
|
||||
get_property(FLAGS DIRECTORY PROPERTY COMPILE_OPTIONS)
|
||||
|
||||
10
README.md
10
README.md
@@ -19,15 +19,23 @@ PMT is designed for developers, technicians, and Android enthusiasts who need fi
|
||||
- **Reboot** the device into multiple modes (normal, recovery, etc.).
|
||||
- **Asynchronous processing** for speed — each partition runs in its own thread.
|
||||
- **Error isolation** so one failing operation doesn’t cancel the rest. For back upping, flashing and erasing.
|
||||
- **Test** sequential read/write speed of your memory.
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
Detailed usage instructions and option references can be found in the [USAGE.md](./USAGE.md) file.
|
||||
For all information about PMT, see the [wiki](https://github.com/ShawkTeam/pmt-renovated/wiki).\
|
||||
Read [Wiki - Using PMT via Termux or ADB](https://github.com/ShawkTeam/pmt-renovated/wiki/Using-PMT-via-Termux-or-ADB) for learn how to use PMT via Termux or ADB.\
|
||||
Detailed usage instructions and option references can be found in the [Wiki - Usage](https://github.com/ShawkTeam/pmt-renovated/wiki/Usage).\
|
||||
See [Wiki - How To Build](https://github.com/ShawkTeam/pmt-renovated/wiki/How-To-Build) to learn how to build.
|
||||
|
||||
## Bug Reporting
|
||||
Please submit bugs at [Issues](https://github.com/ShawkTeam/pmt-renovated/issues) page.
|
||||
|
||||
---
|
||||
|
||||
## Credits
|
||||
- [CLI11: Command line parser for C++11](https://github.com/CLIUtils/CLI11)
|
||||
- [PicoSHA2: A header-file-only, SHA256 hash generator in C++](https://github.com/okdshin/PicoSHA2)
|
||||
- [nlohmann/json: JSON for Modern C++](https://github.com/nlohmann/json)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
# Release Types
|
||||
|
||||
This project provides four different release packages, each tailored for specific Android device architectures and usage preferences.
|
||||
|
||||
---
|
||||
|
||||
## The Four Release Files
|
||||
|
||||
| File Name | Architecture | Bitness | Library Type | Description |
|
||||
|---------------------------|-----------------|---------|----------------|----------------------------------------------------------|
|
||||
| `pmt-arm64-v8a.zip` | ARM64 (ARMv8-A) | 64-bit | Dynamic (.so) | For 64-bit devices, uses dynamic libraries. Requires accompanying `.so` files (`libhelper` and `libpartition_map`). |
|
||||
| `pmt-static-arm64-v8a.zip`| ARM64 (ARMv8-A) | 64-bit | Static (.a) | Fully static build for 64-bit devices. No external dependencies. Great for general use and ADB environments. |
|
||||
| `pmt-armeabi-v7a.zip` | ARM (ARMv7) | 32-bit | Dynamic (.so) | For 32-bit devices, uses dynamic libraries. Requires `.so` files (`libhelper` and `libpartition_map`). |
|
||||
| `pmt-static-armeabi-v7a.zip`| ARM (ARMv7) | 32-bit | Static (.a) | Fully static build for 32-bit devices. No external dependencies. Great for general use and ADB environments. |
|
||||
|
||||
---
|
||||
|
||||
## Architecture & Bitness Explained
|
||||
|
||||
- **ARM64 (arm64-v8a)**:
|
||||
This is a 64-bit architecture used by newer Android devices. It can handle larger amounts of memory and generally runs faster for heavy tasks.
|
||||
|
||||
- **ARM (armeabi-v7a)**:
|
||||
This is a 32-bit architecture common on older or less powerful Android devices. It has some limitations compared to 64-bit but is still widely supported.
|
||||
|
||||
---
|
||||
|
||||
## Dynamic vs Static Libraries
|
||||
|
||||
The project relies on two helper libraries:
|
||||
- **libhelper**
|
||||
- **libpartition_map**
|
||||
|
||||
### Dynamic Versions (`.so` files)
|
||||
|
||||
- In the non-static (`pmt-arm64-v8a.zip` and `pmt-armeabi-v7a.zip`) packages, these libraries are **compiled as shared objects (`.so` files)**.
|
||||
- This means that the main program (`pmt`) **depends on these libraries being present** on the device or alongside the executable to run correctly.
|
||||
- If these libraries are missing, the program will fail to start.
|
||||
- These builds are mostly for developers or users who want to customize or work closely with the libraries.
|
||||
|
||||
### Static Versions (`.a` files)
|
||||
|
||||
- The static packages (`pmt-static-arm64-v8a.zip` and `pmt-static-armeabi-v7a.zip`) **include these libraries inside the main executable** by linking them statically.
|
||||
- This means the `pmt` binary is **completely self-contained** and **does not require any external `.so` files**.
|
||||
- These versions are ideal for general users and especially convenient for ADB usage, where installing separate `.so` files might be cumbersome.
|
||||
|
||||
---
|
||||
|
||||
## Which Should You Use?
|
||||
|
||||
- If you want a hassle-free experience and don’t want to worry about missing libraries, **choose the static version** matching your device’s architecture.
|
||||
- If you are a developer or want to experiment with the libraries separately, or save space by sharing `.so` files between multiple programs, the **dynamic version** is the way to go.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Release Type | Architecture | Dependencies | Best For |
|
||||
|--------------|--------------|-----------------------|---------------------------|
|
||||
| Static | 32-bit / 64-bit | None (fully standalone) | General users, ADB usage |
|
||||
| Dynamic | 32-bit / 64-bit | Requires `.so` libs | Developers, advanced users |
|
||||
|
||||
---
|
||||
|
||||
If you’re unsure which one to pick, try the **static version** first — it works out of the box on all supported devices.
|
||||
319
USAGE.md
319
USAGE.md
@@ -1,319 +0,0 @@
|
||||
# Partition Manager Tool (PMT)
|
||||
|
||||
**Partition Manager Tool** is a powerful command-line utility for **Android** devices, designed to perform various operations on partitions quickly, reliably, and efficiently.
|
||||
This is the **renovated version** of PMT, rewritten in C++ for improved performance, stability, and usability compared to its older variant.
|
||||
|
||||
It supports **asynchronous operations**, allowing multiple partitions to be processed in parallel, and includes safety measures to prevent a single error from breaking the entire operation batch.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Backup** partitions to files (with optional permissions fix for non-root access).
|
||||
- **Flash** image files directly to partitions.
|
||||
- **Erase** partitions by filling them with zero bytes.
|
||||
- **Get** partition sizes in various units.
|
||||
- **Display** partition information in plain text or JSON format.
|
||||
- **Retrieve** real paths and symbolic link paths of partitions.
|
||||
- **Identify** file system or image types by checking magic numbers.
|
||||
- **Reboot** the device into different modes.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
Don't forget to check out how to use it with **ADB**!
|
||||
|
||||
```bash
|
||||
pmt [OPTIONS] [SUBCOMMAND]
|
||||
```
|
||||
|
||||
### Global Options
|
||||
|
||||
| Option | Long Option | Description |
|
||||
|--------|------------------------|-------------|
|
||||
| `-h` | `--help` | Print basic help message and exit. |
|
||||
| | `--help-all` | Print full help message and exit. |
|
||||
| `-S` | `--search-path TEXT` | Set the partition search path. |
|
||||
| `-L` | `--log-file TEXT` | Set log file path. |
|
||||
| `-f` | `--force` | Force the process to be executed even if checks fail. |
|
||||
| `-l` | `--logical` | Specify that the target partition is **dynamic**. |
|
||||
| `-q` | `--quiet` | Suppress output. |
|
||||
| `-V` | `--verbose` | Enable detailed logs during execution. |
|
||||
| `-v` | `--version` | Print version and exit. |
|
||||
|
||||
**Example usages for global options:**\
|
||||
`pmt [SUBCOMMAND ...] --quiet`\
|
||||
`pmt [SUBCOMMAND ...] -S /dev/block/platform/bootdevice/by-name`\
|
||||
`pmt [SUBCOMMAND ...] [GLOBAL OPTIONS ...]`
|
||||
|
||||
---
|
||||
|
||||
## Subcommands
|
||||
|
||||
### 1. `backup`
|
||||
Backup partitions to files. General syntax:
|
||||
```bash
|
||||
pmt backup partition(s) [output(s)] [OPTIONS]
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `-b`, `--buffer-size SIZE` → Set buffer size (in bytes) for read/write operations.
|
||||
- `-O`, `--output-directory DIR` → Specify an output directory for backups.
|
||||
|
||||
**Notes:**
|
||||
- Partition names are separated by commas.
|
||||
- If custom output names are provided, they must match the number of partitions.
|
||||
- Automatically adjusts permissions so backup files can be read/written without root.
|
||||
|
||||
**Example usages:**\
|
||||
`pmt backup boot`\
|
||||
`pmt backup boot boot_backup.img`\
|
||||
`pmt backup boot,recovery,vendor`\
|
||||
`pmt backup boot`\
|
||||
`pmt backup boot,recovery -O /sdcard`\
|
||||
`pmt backup system,vendor --buffer-size=8192 # '=' is not mandatory`
|
||||
|
||||
---
|
||||
|
||||
### 2. `flash`
|
||||
Flash an image or multiple images to partitions. general syntax:
|
||||
```bash
|
||||
pmt flash partition(s) image(s) [OPTIONS]
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `-b`, `--buffer-size SIZE` → Set buffer size (in bytes).
|
||||
- `-I`, `--image-directory DIR` → Directory containing image files.
|
||||
|
||||
**Notes:**
|
||||
- Multiple partitions and images are separated by commas.
|
||||
|
||||
- **Example usages:**\
|
||||
`pmt flash boot boot_backup.img`\
|
||||
`pmt flash boot,recovery /sdcard/backups/boot_backup.img,/sdcard/backups/recovery_backup.img`\
|
||||
`pmt flash boot boot_backup.img,recovery_backup.img -I /sdcard/backups`\
|
||||
`pmt flash system,vendor system_backup.img,vendor_backup.img -I /sdcard/backups --buffer-size=8192`
|
||||
|
||||
---
|
||||
|
||||
### 3. `erase`
|
||||
Fill partition(s) with zero bytes (like `dd if=/dev/zero of=/dev/block/by-name/<partition>`). General syntax:
|
||||
```bash
|
||||
pmt erase partition(s) [OPTIONS]
|
||||
```
|
||||
**Options:**
|
||||
- `-b`, `--buffer-size SIZE` → Set buffer size.
|
||||
|
||||
**Example usages (DO NOT USE FOR TRYING!!!):**\
|
||||
`pmt erase boot`\
|
||||
`pmt erase nvdata,nvram`\
|
||||
`pmt erase system,vendor --buffer-size=8192`
|
||||
|
||||
---
|
||||
|
||||
### 4. `sizeof`
|
||||
Show the size of partition(s). General syntax:
|
||||
```bash
|
||||
pmt sizeof partition(s) [OPTIONS]
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `--as-byte` → Show size in bytes.
|
||||
- `--as-kilobyte` → Show size in KB.
|
||||
- `--as-megabyte` → Show size in MB (default).
|
||||
- `--as-gigabyte` → Show size in GB.
|
||||
- `--only-size` → Output only the numeric value (no partition name).
|
||||
|
||||
**Example usages:**\
|
||||
`pmt sizeof boot` - Example output: `boot: 64MB`\
|
||||
`pmt sizeof boot --as-byte` - Example output: `64`\
|
||||
`pmt sizeof boot --as-<write type here> --only-size` - Example output (for `--as-kilobyte`): `98304`
|
||||
|
||||
---
|
||||
|
||||
### 5. `info`
|
||||
Show partition name, size, and dynamic status. General syntax:
|
||||
```bash
|
||||
pmt info partition(s) [OPTIONS]
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `-J`, `--json` → Output in JSON format.
|
||||
- `--json-partition-name NAME` → Custom JSON key for partition name.
|
||||
- `--json-size-name NAME` → Custom JSON key for size.
|
||||
- `--json-logical-name NAME` → Custom JSON key for dynamic status.
|
||||
|
||||
**Example usages:**\
|
||||
`pmt info boot` - Example output: `partition=boot size=100663296 isLogical=false`\
|
||||
`pmt info boot -J` - Example output: `{"name": "boot", "size": 100663296, "isLogical": false}`\
|
||||
`pmt info boot -J --json-partition-name=partitionName` - Example output: `{"partitionName": "boot", "size": 100663296, "isLogical": false}`
|
||||
|
||||
---
|
||||
|
||||
### 6. `real-path`
|
||||
Show the **absolute block device path** for each partition. General syntax:
|
||||
```bash
|
||||
pmt real-path partition(s) [OPTIONS]
|
||||
```
|
||||
|
||||
**Example usages:**\
|
||||
`pmt real-path boot` - Example output: `/dev/block/sda25`
|
||||
|
||||
---
|
||||
|
||||
### 7. `real-linkpath`
|
||||
Show the **symbolic link path** for each partition (e.g., `/dev/block/by-name/boot`). General syntax:
|
||||
```bash
|
||||
pmt real-link-path partition(s) [OPTIONS]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. `type`
|
||||
Check magic numbers to determine file system or other types of partition(s) or image(s). General syntax:
|
||||
```bash
|
||||
pmt type partition(s) [OPTIONS]
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `-b`, `--buffer-size SIZE` → Set buffer size.
|
||||
- `--only-check-android-magics` → Check only Android-related magic numbers.
|
||||
- `--only-check-filesystem-magic` → Check only file system magic numbers.
|
||||
|
||||
**Example usages:**\
|
||||
`pmt type boot` - Example output: `boot contains Android Boot Image magic (0x2144494F52444241)`\
|
||||
`pmt type vendor_boot.img` - Example output: `vendor_boot.img contains Android Vendor Boot Image magic (0x544F4F4252444E56)`
|
||||
|
||||
---
|
||||
|
||||
### 9. `reboot`
|
||||
Reboot the device. Default reboot target is normal. If you are using it via ADB terminal, you **DO NOT** need root to use this feature. General syntax:
|
||||
```bash
|
||||
pmt reboot [rebootTarget] [OPTIONS]
|
||||
```
|
||||
|
||||
**Example usages:**\
|
||||
`pmt reboot`
|
||||
`pmt reboot recovery`
|
||||
`pmt reboot download`
|
||||
|
||||
## Additional Notes
|
||||
|
||||
- **Comma-separated inputs**: All commands (except `reboot`) require multiple inputs to be separated by commas.
|
||||
- **Asynchronous execution**: For `backup`, `flash`, and `erase`, each partition is processed in a separate thread for maximum speed.
|
||||
- **Error isolation**: A failure in processing one partition will not cancel the others. Only for `backup`, `flash` and `erase` functions.
|
||||
- **Automatic diagnostics**: By default, whether a partition is dynamic or regular is determined automatically. With global options, you only specify precision.
|
||||
- **Root access**: Root access is required if operations are to be performed on partitions.
|
||||
|
||||
## Extra Note: Comma Usage
|
||||
|
||||
In **Partition Manager Tool**, whenever you provide **multiple partitions**, **multiple image files**, or **multiple output file names**, they **must** be separated by commas (`,`), without spaces.
|
||||
|
||||
✅ **Correct:**\
|
||||
`pmt backup boot,recovery`\
|
||||
`pmt flash boot,recovery boot.img,recovery.img`
|
||||
|
||||
|
||||
❌ **Incorrect:**\
|
||||
`pmt backup boot recovery`\
|
||||
`pmt flash boot recovery boot.img recovery.img`
|
||||
|
||||
The **number of items must match** when providing both input and output lists.
|
||||
For example, if you specify 3 partitions, you must also provide 3 output file names.
|
||||
|
||||
This rule applies to **all commands except `reboot`**, since `reboot` only takes one optional argument.
|
||||
|
||||
---
|
||||
|
||||
## Using `pmt-static` via ADB
|
||||
|
||||
This guide will show you how to use the **static** version of Partition Manager Tool (`pmt-static`) on your Android device through **ADB**.
|
||||
It’s written for beginners — no advanced knowledge needed.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Why Static Version?
|
||||
The **static** build of PMT contains everything it needs inside one single file.
|
||||
This means you can run it directly on your Android device **without** installing extra libraries.
|
||||
Perfect for quick tasks via ADB.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Requirements
|
||||
- **ADB installed** on your computer
|
||||
(Part of the Android SDK Platform Tools — [Download here](https://developer.android.com/studio/releases/platform-tools))
|
||||
- **USB Debugging enabled** on your phone
|
||||
(Settings → Developer options → Enable USB debugging)
|
||||
- Your **phone connected via USB** and recognized by ADB
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Step-by-Step Usage
|
||||
|
||||
### 1️⃣ Get the Correct Binary
|
||||
Download the **`pmt-static`** file that matches your device’s architecture:
|
||||
- **`pmt-static-arm64-v8a`** → For 64-bit devices
|
||||
- **`pmt-static-armeabi-v7a`** → For 32-bit devices
|
||||
|
||||
Unzip the downloaded `.zip` file — you should now have a `pmt` binary.
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ Push the Binary to Your Device
|
||||
Use ADB to copy the `pmt` file to your phone’s temporary folder:
|
||||
```bash
|
||||
# Rename for more easily usage
|
||||
mv pmt_static pmt
|
||||
|
||||
adb push pmt /data/local/tmp/pmt
|
||||
```
|
||||
|
||||
### 3️⃣ Open an ADB Shell
|
||||
Access your device shell:
|
||||
```bash
|
||||
adb shell
|
||||
```
|
||||
|
||||
### 4️⃣ Change to the Directory
|
||||
Move into the temporary directory where pmt is stored:
|
||||
```bash
|
||||
cd /data/local/tmp
|
||||
```
|
||||
|
||||
### 5️⃣ Give Execute Permission
|
||||
Allow the binary to be executed:
|
||||
```bash
|
||||
chmod 755 pmt
|
||||
```
|
||||
|
||||
### 6️⃣ Run PMT
|
||||
You can now run PMT directly from this directory:
|
||||
|
||||
```bash
|
||||
# Open root terminal
|
||||
su
|
||||
|
||||
./pmt --help
|
||||
```
|
||||
Example — Back up the boot partition:
|
||||
|
||||
```bash
|
||||
./pmt backup boot
|
||||
```
|
||||
|
||||
### 💡 Tips
|
||||
Commands must be run from /data/local/tmp unless you move pmt elsewhere.\
|
||||
The /data/local/tmp folder is cleared when you reboot your device.\
|
||||
Static builds are completely standalone — no missing library issues.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
Partition Manager Tool is licensed under the **Apache 2.0 License**.
|
||||
Copyright © YZBruh.
|
||||
|
||||
---
|
||||
|
||||
## Bug Reports
|
||||
Please submit issues at:
|
||||
[https://github.com/ShawkTeam/pmt-renovated/issues](https://github.com/ShawkTeam/pmt-renovated/issues)
|
||||
67
build.sh
67
build.sh
@@ -15,74 +15,65 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
BUILD_64="build_arm64-v8a"
|
||||
BUILD_32="build_armeabi-v7a"
|
||||
THIS="$(basename $0)"
|
||||
TARGET_ABI_LIST=("arm64-v8a" "armeabi-v7a")
|
||||
|
||||
echo() { command echo "[$THIS]: $@"; }
|
||||
|
||||
checks()
|
||||
{
|
||||
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
|
||||
if ! which cmake &>/dev/null; then
|
||||
echo "Please verify your CMake installation."
|
||||
exit 1
|
||||
fi
|
||||
if ! which ninja &>/dev/null; then
|
||||
echo "Please verify your Ninja installation."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
clean()
|
||||
{
|
||||
clean() {
|
||||
echo "Cleaning workspace."
|
||||
rm -rf $BUILD_32 $BUILD_64 \
|
||||
include/generated \
|
||||
for a in ${TARGET_ABI_LIST[@]}; do rm -rf build_$a; done
|
||||
rm -rf include/generated \
|
||||
srclib/libhelper/tests/dir \
|
||||
srclib/libhelper/tests/linkdir \
|
||||
srclib/libhelper/tests/file.txt
|
||||
}
|
||||
|
||||
build()
|
||||
{
|
||||
mkdir -p $BUILD_64 $BUILD_32
|
||||
build() {
|
||||
set -e
|
||||
command echo -e "BUILD INFO:
|
||||
ARCHS: arm64-v8a armeabi-v7a
|
||||
ARCHS: ${TARGET_ABI_LIST[@]}
|
||||
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 \
|
||||
-DANDROID_STL=c++_static
|
||||
for a in ${TARGET_ABI_LIST[@]}; do
|
||||
echo "Configuring for $a..."
|
||||
mkdir -p build_$a
|
||||
cmake -B build_$a -G Ninja -S . $1 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=$a \
|
||||
-DANDROID_PLATFORM=$ANDROID_PLATFORM \
|
||||
-DANDROID_STL=c++_static
|
||||
done
|
||||
|
||||
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 \
|
||||
-DANDROID_STL=c++_static
|
||||
|
||||
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"
|
||||
for a in ${TARGET_ABI_LIST[@]}; do
|
||||
echo "Building $a artifacts... Using $(($(nproc) - 2)) thread."
|
||||
cmake --build build_$a -j$(($(nproc) - 2))
|
||||
echo "$a build complete, artifacts: $PWD/build_$a"
|
||||
done
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
command echo "Usage: $0 build|rebuild|clean [EXTRA_CMAKE_FLAGS] [ANDROID_PLATFORM=SELECTED_ANDROID_PLATFORM]"
|
||||
command echo -e "Usage: $0 build|rebuild|clean [EXTRA_CMAKE_FLAGS]\n HINT: Export ANDROID_PLATFORM if you set min Android target.\n HINT: Change TARGET_ABI_LIST array in build.sh if you build other archs."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $ANDROID_PLATFORM ]; then ANDROID_PLATFORM="android-21"; fi
|
||||
|
||||
[ -z $ANDROID_PLATFORM ] && ANDROID_PLATFORM="android-21"
|
||||
checks
|
||||
|
||||
case $1 in
|
||||
|
||||
@@ -3902,9 +3902,9 @@ get_default_flag_values(const std::string &str);
|
||||
|
||||
/// Get a vector of short names, one of long names, and a single name
|
||||
CLI11_INLINE
|
||||
std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
|
||||
get_names(const std::vector<std::string> &input,
|
||||
bool allow_non_standard = false);
|
||||
std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
|
||||
get_names(const std::vector<std::string> &input,
|
||||
bool allow_non_standard = false);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -3995,8 +3995,8 @@ get_default_flag_values(const std::string &str) {
|
||||
}
|
||||
|
||||
CLI11_INLINE
|
||||
std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
|
||||
get_names(const std::vector<std::string> &input, bool allow_non_standard) {
|
||||
std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
|
||||
get_names(const std::vector<std::string> &input, bool allow_non_standard) {
|
||||
|
||||
std::vector<std::string> short_names;
|
||||
std::vector<std::string> long_names;
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
#ifndef LIBPMT_LIB_HPP
|
||||
#define LIBPMT_LIB_HPP
|
||||
|
||||
#include <CLI/CLI11.hpp>
|
||||
#include <libhelper/lib.hpp>
|
||||
#include <libpartition_map/lib.hpp>
|
||||
#include <CLI/CLI11.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -28,76 +28,18 @@
|
||||
#define PMTE "pmt"
|
||||
#define PMTF "libpmt-function-manager"
|
||||
|
||||
// Quick access to variables.
|
||||
#define VARS (*Variables)
|
||||
// Quick access to partition map.
|
||||
#define PART_MAP (*VARS.PartMap)
|
||||
|
||||
namespace PartitionManager {
|
||||
// All function classes must inherit from this class.
|
||||
class basic_function {
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
virtual bool init(CLI::App &_app) = 0;
|
||||
virtual bool run() = 0;
|
||||
|
||||
[[nodiscard]] virtual bool isUsed() const = 0;
|
||||
[[nodiscard]] virtual const char *name() const = 0;
|
||||
|
||||
virtual ~basic_function() = default;
|
||||
};
|
||||
|
||||
// A class for function management.
|
||||
class basic_function_manager final {
|
||||
private:
|
||||
std::vector<std::unique_ptr<basic_function>> _functions;
|
||||
|
||||
public:
|
||||
void registerFunction(std::unique_ptr<basic_function> _func, CLI::App &_app);
|
||||
|
||||
[[nodiscard]] bool isUsed(std::string name) const;
|
||||
[[nodiscard]] bool handleAll() const;
|
||||
};
|
||||
|
||||
class basic_variables final {
|
||||
public:
|
||||
basic_variables();
|
||||
~basic_variables();
|
||||
|
||||
PartitionMap::BuildMap *PartMap;
|
||||
|
||||
std::string searchPath, logFile;
|
||||
bool onLogical;
|
||||
bool quietProcess;
|
||||
bool verboseMode;
|
||||
bool viewVersion;
|
||||
bool forceProcess;
|
||||
};
|
||||
|
||||
class variableProtect final {
|
||||
private:
|
||||
basic_variables *_ptr = nullptr;
|
||||
|
||||
public:
|
||||
variableProtect();
|
||||
~variableProtect();
|
||||
|
||||
void setVariablePointer(basic_variables *&_ptr);
|
||||
};
|
||||
|
||||
using FunctionBase = basic_function;
|
||||
using FunctionManager = basic_function_manager;
|
||||
using VariableTable = basic_variables;
|
||||
using Error = Helper::Error;
|
||||
|
||||
extern VariableTable *Variables;
|
||||
|
||||
int Main(int argc, char **argv);
|
||||
|
||||
// Print messages if not using quiet mode
|
||||
__attribute__((format(printf, 1, 2))) void print(const char *format, ...);
|
||||
__attribute__((format(printf, 1, 2))) void println(const char *format, ...);
|
||||
|
||||
// Format it input and return as std::string
|
||||
__attribute__((format(printf, 1, 2))) std::string format(const char *format,
|
||||
...);
|
||||
|
||||
// If there is a delimiter in the string, CLI::detail::split returns; if not, an
|
||||
// empty vector is returned. And checks duplicate arguments.
|
||||
std::vector<std::string> splitIfHasDelim(const std::string &s, char delim,
|
||||
@@ -111,12 +53,118 @@ void processCommandLine(std::vector<std::string> &vec1,
|
||||
bool checkForBadUsage = false);
|
||||
|
||||
// Setting ups buffer size
|
||||
void setupBufferSize(int &size, const std::string &partition);
|
||||
void setupBufferSize(uint64_t &size, const std::string &entry);
|
||||
|
||||
std::string getLibVersion();
|
||||
|
||||
std::string getAppVersion(); // Not Android app version (an Android app is
|
||||
// planned!), tells pmt version.
|
||||
|
||||
enum basic_function_flags {
|
||||
NO_SU = 1,
|
||||
NO_MAP_CHECK = 2,
|
||||
ADB_SUFFICIENT = 3,
|
||||
};
|
||||
|
||||
// All function classes must inherit from this class.
|
||||
class basic_function {
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
std::vector<int> flags = {};
|
||||
|
||||
virtual bool init(CLI::App &_app) = 0;
|
||||
virtual bool run() = 0;
|
||||
|
||||
[[nodiscard]] virtual bool isUsed() const = 0;
|
||||
[[nodiscard]] virtual const char *name() const = 0;
|
||||
|
||||
virtual ~basic_function() = default;
|
||||
};
|
||||
|
||||
// A class for function management.
|
||||
template <class _Type> class basic_manager {
|
||||
private:
|
||||
std::vector<std::unique_ptr<_Type>> _functions;
|
||||
|
||||
public:
|
||||
void registerFunction(std::unique_ptr<_Type> _func, CLI::App &_app) {
|
||||
LOGN(PMTF, INFO) << "registering: " << _func->name() << std::endl;
|
||||
for (const auto &f : _functions) {
|
||||
if (std::string(_func->name()) == std::string(f->name())) {
|
||||
LOGN(PMTF, INFO) << "Is already registered: " << _func->name()
|
||||
<< ". Skipping." << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!_func->init(_app))
|
||||
throw Helper::Error("Cannot init: %s", _func->name());
|
||||
_functions.push_back(std::move(_func));
|
||||
LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasFlagOnUsedFunction(int flag) const {
|
||||
for (const auto &func : _functions) {
|
||||
if (func->isUsed()) {
|
||||
std::for_each(func->flags.begin(), func->flags.end(), [&](const int x) {
|
||||
LOGN(PMTF, INFO) << "Used flag " << x << " on " << func->name()
|
||||
<< std::endl;
|
||||
});
|
||||
return std::find(func->flags.begin(), func->flags.end(), flag) !=
|
||||
func->flags.end();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isUsed(const std::string &name) const {
|
||||
if (_functions.empty()) return false;
|
||||
for (const auto &func : _functions) {
|
||||
if (func->name() == name) return func->isUsed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool handleAll() const {
|
||||
LOGN(PMTF, INFO) << "running caught commands in command-line." << std::endl;
|
||||
for (const auto &func : _functions) {
|
||||
if (func->isUsed()) {
|
||||
LOGN(PMTF, INFO) << func->name()
|
||||
<< " is calling because used in command-line."
|
||||
<< std::endl;
|
||||
return func->run();
|
||||
}
|
||||
}
|
||||
|
||||
LOGN(PMTF, INFO) << "not found any used function from command-line."
|
||||
<< std::endl;
|
||||
println("Target progress is not specified. Specify a progress.");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class basic_variables final {
|
||||
public:
|
||||
basic_variables();
|
||||
|
||||
std::unique_ptr<PartitionMap::BuildMap> PartMap;
|
||||
|
||||
std::string searchPath, logFile;
|
||||
bool onLogical;
|
||||
bool quietProcess;
|
||||
bool verboseMode;
|
||||
bool viewVersion;
|
||||
bool forceProcess;
|
||||
};
|
||||
|
||||
using FunctionBase = basic_function;
|
||||
using FunctionManager = basic_manager<FunctionBase>;
|
||||
using FunctionFlags = basic_function_flags;
|
||||
using VariableTable = basic_variables;
|
||||
using Error = Helper::Error;
|
||||
|
||||
extern std::unique_ptr<VariableTable> Variables;
|
||||
extern FILE *pstdout, *pstderr;
|
||||
} // namespace PartitionManager
|
||||
|
||||
#endif // #ifndef LIBPMT_LIB_HPP
|
||||
|
||||
21
include/nlohmann/LICENSE
Normal file
21
include/nlohmann/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2025 Niels Lohmann
|
||||
|
||||
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.
|
||||
25521
include/nlohmann/json.hpp
Normal file
25521
include/nlohmann/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
187
include/nlohmann/json_fwd.hpp
Normal file
187
include/nlohmann/json_fwd.hpp
Normal file
@@ -0,0 +1,187 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <map> // map
|
||||
#include <memory> // allocator
|
||||
#include <string> // string
|
||||
#include <vector> // vector
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
// This file contains all macro definitions affecting or depending on the ABI
|
||||
|
||||
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0
|
||||
#warning "Already included a different version of the library!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum)
|
||||
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DIAGNOSTIC_POSITIONS
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTICS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
_v ## major ## _ ## minor ## _ ## patch
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
|
||||
|
||||
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION
|
||||
#else
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
|
||||
NLOHMANN_JSON_VERSION_MINOR, \
|
||||
NLOHMANN_JSON_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
// Combine namespace components
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE
|
||||
#define NLOHMANN_JSON_NAMESPACE \
|
||||
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION)
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
|
||||
namespace nlohmann \
|
||||
{ \
|
||||
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION) \
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_END
|
||||
#define NLOHMANN_JSON_NAMESPACE_END \
|
||||
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
|
||||
} // namespace nlohmann
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
@brief namespace for Niels Lohmann
|
||||
@see https://github.com/nlohmann
|
||||
@since version 1.0.0
|
||||
*/
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
/*!
|
||||
@brief default JSONSerializer template argument
|
||||
|
||||
This serializer ignores the template arguments and uses ADL
|
||||
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||
for serialization.
|
||||
*/
|
||||
template<typename T = void, typename SFINAE = void>
|
||||
struct adl_serializer;
|
||||
|
||||
/// a class to store JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/
|
||||
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||
std::map,
|
||||
template<typename U, typename... Args> class ArrayType = std::vector,
|
||||
class StringType = std::string, class BooleanType = bool,
|
||||
class NumberIntegerType = std::int64_t,
|
||||
class NumberUnsignedType = std::uint64_t,
|
||||
class NumberFloatType = double,
|
||||
template<typename U> class AllocatorType = std::allocator,
|
||||
template<typename T, typename SFINAE = void> class JSONSerializer =
|
||||
adl_serializer,
|
||||
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
|
||||
class CustomBaseClass = void>
|
||||
class basic_json;
|
||||
|
||||
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/
|
||||
template<typename RefStringType>
|
||||
class json_pointer;
|
||||
|
||||
/*!
|
||||
@brief default specialization
|
||||
@sa https://json.nlohmann.me/api/json/
|
||||
*/
|
||||
using json = basic_json<>;
|
||||
|
||||
/// @brief a minimal map-like container that preserves insertion order
|
||||
/// @sa https://json.nlohmann.me/api/ordered_map/
|
||||
template<class Key, class T, class IgnoredLess, class Allocator>
|
||||
struct ordered_map;
|
||||
|
||||
/// @brief specialization that maintains the insertion order of object keys
|
||||
/// @sa https://json.nlohmann.me/api/ordered_json/
|
||||
using ordered_json = basic_json<nlohmann::ordered_map>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
35
manager.sh
35
manager.sh
@@ -1,4 +1,3 @@
|
||||
#!/data/data/com.termux/files/usr/bin/env bash
|
||||
#
|
||||
# Copyright 2025 Yağız Zengin
|
||||
#
|
||||
@@ -16,7 +15,7 @@
|
||||
#
|
||||
|
||||
THIS="$(basename $0)"
|
||||
RELEASE="20250811"
|
||||
RELEASE="20250821"
|
||||
|
||||
echo() { command echo "[$THIS]: $@"; }
|
||||
|
||||
@@ -37,26 +36,25 @@ select_variant()
|
||||
{
|
||||
LINK=""; ARCH=""; VARIANT=""
|
||||
|
||||
if getprop ro.product.cpu.abi | grep "arm64-v8a" &>/dev/null; then ARCH="arm64-v8a";
|
||||
if getprop ro.product.cpu.abi | grep "arm64-v8a" &>/dev/null; then ARCH="arm64-v8a"
|
||||
else ARCH="armeabi-v7a"
|
||||
fi
|
||||
[ $1 == "static" ] && VARIANT="static-"
|
||||
if grep "static" <<< $1 &>/dev/null; then VARIANT="static-"; fi
|
||||
|
||||
LINK="https://github.com/ShawkTeam/pmt-renovated/releases/download/${RELEASE}/pmt-${VARIANT}${ARCH}.zip"
|
||||
LINK="https://github.com/ShawkTeam/pmt-renovated/releases/download/${RELEASE}/pmt-${VARIANT}${ARCH}.zip"
|
||||
}
|
||||
|
||||
download()
|
||||
{
|
||||
mkdir -p $PREFIX/tmp
|
||||
echo "Downloading pmt-${VARIANT}${ARCH}.zip (${RELEASE})"
|
||||
if ! wget -o $PREFIX/tmp/pmt.zip "${LINK}" &>/dev/null; then
|
||||
if ! wget -O $PREFIX/tmp/pmt.zip "${LINK}" &>/dev/null; then
|
||||
echo "Download failed! LINK=${LINK}"
|
||||
rm $PREFIX/tmp/*.zip
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Extracting..."
|
||||
if ! unzip -d $PREFIX/tmp $PREFIX/tmp/pmt.zip &>/dev/null; then
|
||||
if ! unzip -o -d $PREFIX/tmp $PREFIX/tmp/pmt.zip &>/dev/null; then
|
||||
echo "Extraction failed!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -64,7 +62,7 @@ download()
|
||||
|
||||
setup()
|
||||
{
|
||||
[ -f $PREFIX/tmp/pmt_static ]; mv $PREFIX/tmp/pmt_static $PREFIX/tmp/pmt
|
||||
[ -f $PREFIX/tmp/pmt_static ] && mv $PREFIX/tmp/pmt_static $PREFIX/tmp/pmt
|
||||
set -e
|
||||
install -t $PREFIX/bin $PREFIX/tmp/pmt
|
||||
if [ -f $PREFIX/tmp/libhelper.so ]; then
|
||||
@@ -76,7 +74,7 @@ setup()
|
||||
|
||||
uninstall()
|
||||
{
|
||||
rm -f $PREFIX/bin7pmt $PREFIX/lib/libhelper* $PREFIX/lib/libpartition_map* &>/dev/null
|
||||
rm -f $PREFIX/bin/pmt $PREFIX/lib/libhelper* $PREFIX/lib/libpartition_map* &>/dev/null
|
||||
}
|
||||
|
||||
is_installed()
|
||||
@@ -97,11 +95,16 @@ if [ $# -eq 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! basename -a ${PREFIX}/bin/* | grep "termux" &>/dev/null; then
|
||||
echo "This script only for termux!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
"install")
|
||||
is_installed
|
||||
checks
|
||||
select_variant $([ "$2" == "--static" ] && echo static)
|
||||
select_variant $(grep "static" <<< $2 &>/dev/null && command echo static)
|
||||
download
|
||||
setup
|
||||
;;
|
||||
@@ -109,13 +112,13 @@ case $1 in
|
||||
uninstall && echo "Uninstalled successfully."
|
||||
;;
|
||||
"reinstall")
|
||||
uninstall
|
||||
checks
|
||||
select_variant $([ "$2" == "--static" ] && echo static)
|
||||
uninstall
|
||||
checks
|
||||
select_variant $(grep "static" <<< $2 &>/dev/null && command echo static)
|
||||
download
|
||||
setup
|
||||
;;
|
||||
*)
|
||||
command echo "$0: Unknown argument: $1"
|
||||
exit 1 ;;
|
||||
command echo "$0: Unknown argument: $1"
|
||||
exit 1 ;;
|
||||
esac
|
||||
|
||||
@@ -19,18 +19,20 @@ set(PMT_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PartitionManager.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/BackupFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/CleanLogFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/EraseFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/FlashFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/InfoFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/MemoryTestFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/PartitionSizeFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealPathFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealLinkPathFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/RebootFunction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/functions/TypeFunction.cpp
|
||||
)
|
||||
|
||||
# Add pmt
|
||||
add_executable(pmt ${PMT_SOURCES})
|
||||
add_executable(pmt ${PMT_SOURCES}
|
||||
functions/CleanLogFunction.cpp)
|
||||
add_executable(pmt_static ${PMT_SOURCES})
|
||||
|
||||
# Set linker options
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
#include <algorithm>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -39,12 +40,19 @@ std::vector<std::string> splitIfHasDelim(const std::string &s, const char delim,
|
||||
return vec;
|
||||
}
|
||||
|
||||
void setupBufferSize(int &size, const std::string &partition) {
|
||||
if (Variables->PartMap->sizeOf(partition) % size != 0) {
|
||||
print("%sWARNING%s: Specified buffer size is invalid! Using 1 byte as "
|
||||
"buffer size.",
|
||||
YELLOW, STYLE_RESET);
|
||||
size = 1;
|
||||
void setupBufferSize(uint64_t &size, const std::string &entry) {
|
||||
if (PART_MAP.hasPartition(entry) && PART_MAP.sizeOf(entry) % size != 0) {
|
||||
println("%sWARNING%s: Specified buffer size is invalid for %s! Using "
|
||||
"different buffer size for %s.",
|
||||
YELLOW, STYLE_RESET, entry.data(), entry.data());
|
||||
size = PART_MAP.sizeOf(entry) % 4096 == 0 ? 4096 : 1;
|
||||
} else if (Helper::fileIsExists(entry)) {
|
||||
if (Helper::fileSize(entry) % size != 0) {
|
||||
println("%sWARNING%s: Specified buffer size is invalid for %s! using "
|
||||
"different buffer size for %s.",
|
||||
YELLOW, STYLE_RESET, entry.data(), entry.data());
|
||||
size = Helper::fileSize(entry) % 4096 == 0 ? 4096 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,40 +66,4 @@ void processCommandLine(std::vector<std::string> &vec1,
|
||||
if (vec1.empty() && !s1.empty()) vec1.push_back(s1);
|
||||
if (vec2.empty() && !s2.empty()) vec2.push_back(s2);
|
||||
}
|
||||
|
||||
void basic_function_manager::registerFunction(
|
||||
std::unique_ptr<basic_function> _func, CLI::App &_app) {
|
||||
LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl;
|
||||
if (!_func->init(_app))
|
||||
throw Error("Cannot init function: %s\n", _func->name());
|
||||
_functions.push_back(std::move(_func));
|
||||
LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
bool basic_function_manager::isUsed(const std::string name) const {
|
||||
if (_functions.empty()) return false;
|
||||
for (const auto &func : _functions) {
|
||||
if (func->name() == name) return func->isUsed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool basic_function_manager::handleAll() const {
|
||||
LOGN(PMTF, INFO) << "running caught function commands in command-line."
|
||||
<< std::endl;
|
||||
for (const auto &func : _functions) {
|
||||
if (func->isUsed()) {
|
||||
LOGN(PMTF, INFO) << func->name()
|
||||
<< " is calling because used in command-line."
|
||||
<< std::endl;
|
||||
return func->run();
|
||||
}
|
||||
}
|
||||
|
||||
LOGN(PMTF, INFO) << "not found any used function from command-line."
|
||||
<< std::endl;
|
||||
println("Target progress is not specified. Specify a progress.");
|
||||
return false;
|
||||
}
|
||||
} // namespace PartitionManager
|
||||
|
||||
@@ -18,6 +18,5 @@
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Call integrated main function in library
|
||||
Helper::LoggingProperties::setProgramName(PMTE);
|
||||
return PartitionManager::Main(argc, argv);
|
||||
}
|
||||
|
||||
@@ -16,69 +16,88 @@
|
||||
|
||||
#include "functions/functions.hpp"
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#ifndef ANDROID_BUILD
|
||||
#include <generated/buildInfo.hpp>
|
||||
#endif
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace PartitionManager {
|
||||
variableProtect protector;
|
||||
auto Variables = new VariableTable();
|
||||
|
||||
variableProtect::variableProtect() {
|
||||
Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log");
|
||||
}
|
||||
variableProtect::~variableProtect() { delete _ptr; }
|
||||
void variableProtect::setVariablePointer(basic_variables *&_ptr) {
|
||||
this->_ptr = _ptr;
|
||||
}
|
||||
/**
|
||||
* Register functions. Uses ready 'FuncManager' variable.
|
||||
*
|
||||
* Usage: REGISTER_FUNCTION(FUNCTION_CLASS);
|
||||
*/
|
||||
#define REGISTER_FUNCTION(cls) \
|
||||
FuncManager.registerFunction(std::make_unique<cls>(), AppMain)
|
||||
|
||||
basic_variables::~basic_variables() { delete PartMap; }
|
||||
basic_variables::basic_variables()
|
||||
: logFile("/sdcard/Documents/last_pmt_logs.log"), onLogical(false),
|
||||
: logFile(Helper::LoggingProperties::FILE), onLogical(false),
|
||||
quietProcess(false), verboseMode(false), viewVersion(false),
|
||||
forceProcess(false) {
|
||||
try { PartMap = new PartitionMap::BuildMap(); }
|
||||
catch (std::exception&) {}
|
||||
try {
|
||||
PartMap = std::make_unique<PartitionMap::BuildMap>();
|
||||
} catch (std::exception &) {
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((constructor)) void init() {
|
||||
Helper::LoggingProperties::setProgramName(PMTE);
|
||||
Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log");
|
||||
}
|
||||
|
||||
static void sigHandler(const int sig) {
|
||||
if (sig == SIGINT) println("\n%sInterrupted.%s", YELLOW, STYLE_RESET);
|
||||
if (sig == SIGABRT) println("\n%sAborted.%s", RED, STYLE_RESET);
|
||||
exit(sig);
|
||||
}
|
||||
|
||||
static int write(void *cookie, const char *buf, const int size) {
|
||||
auto *real = static_cast<FILE *>(cookie);
|
||||
if (!VARS.quietProcess) {
|
||||
const int ret = fwrite(buf, 1, static_cast<size_t>(size), real);
|
||||
fflush(real);
|
||||
return ret;
|
||||
} else return size;
|
||||
}
|
||||
|
||||
static FILE *make_fp(FILE *real) {
|
||||
return funopen(real, nullptr, write, nullptr, nullptr);
|
||||
}
|
||||
|
||||
auto Variables = std::make_unique<VariableTable>();
|
||||
FILE *pstdout = make_fp(stdout);
|
||||
FILE *pstderr = make_fp(stderr);
|
||||
|
||||
static Helper::garbageCollector collector;
|
||||
|
||||
int Main(int argc, char **argv) {
|
||||
try {
|
||||
// try-catch start
|
||||
CLI::App AppMain{"Partition Manager Tool"};
|
||||
protector.setVariablePointer(Variables);
|
||||
FunctionManager FuncManager;
|
||||
Helper::LoggingProperties::setProgramName(argv[0]);
|
||||
collector.closeAfterProgress(pstdout);
|
||||
collector.closeAfterProgress(pstderr);
|
||||
|
||||
AppMain.fallthrough(true);
|
||||
AppMain.set_help_all_flag("--help-all", "Print full help message and exit");
|
||||
AppMain.footer("Partition Manager Tool is written by YZBruh\nThis project "
|
||||
"licensed under "
|
||||
"Apache 2.0 license\nReport "
|
||||
"bugs to https://github.com/ShawkTeam/pmt-renovated/issues");
|
||||
AppMain
|
||||
.add_option("-S,--search-path", Variables->searchPath,
|
||||
"Set partition search path")
|
||||
->check([&](const std::string &val) {
|
||||
if (val.find("/block") == std::string::npos)
|
||||
throw CLI::ValidationError(
|
||||
"Partition search path is unexpected! Couldn't find "
|
||||
"'block' in input path!");
|
||||
return std::string();
|
||||
});
|
||||
AppMain.add_option("-L,--log-file", Variables->logFile, "Set log file");
|
||||
AppMain.add_flag("-f,--force", Variables->forceProcess,
|
||||
"Force process to be processed");
|
||||
AppMain.add_flag("-l,--logical", Variables->onLogical,
|
||||
"Specify that the target partition is dynamic");
|
||||
AppMain.add_flag("-q,--quiet", Variables->quietProcess, "Quiet process");
|
||||
AppMain.add_flag("-V,--verbose", Variables->verboseMode,
|
||||
"Detailed information is written on the screen while the "
|
||||
"transaction is "
|
||||
"being carried out");
|
||||
AppMain.add_flag("-v,--version", Variables->viewVersion,
|
||||
"Print version and exit");
|
||||
signal(SIGINT, sigHandler);
|
||||
signal(SIGABRT, sigHandler);
|
||||
|
||||
if (!isatty(fileno(stdin))) {
|
||||
char buf[128];
|
||||
while (fgets(buf, sizeof(buf), stdin) != nullptr) {
|
||||
buf[strcspn(buf, "\n")] = 0;
|
||||
const char *token = strtok(buf, " \t");
|
||||
while (token != nullptr) {
|
||||
argv[argc] = strdup(token);
|
||||
argc++;
|
||||
token = strtok(nullptr, " \t");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
println(
|
||||
@@ -87,46 +106,92 @@ int Main(int argc, char **argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
FuncManager.registerFunction(std::make_unique<backupFunction>(), AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<flashFunction>(), AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<partitionSizeFunction>(),
|
||||
AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<realPathFunction>(), AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<realLinkPathFunction>(),
|
||||
AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<typeFunction>(), AppMain);
|
||||
FuncManager.registerFunction(std::make_unique<rebootFunction>(), AppMain);
|
||||
CLI::App AppMain{"Partition Manager Tool"};
|
||||
FunctionManager FuncManager;
|
||||
|
||||
AppMain.fallthrough(true);
|
||||
AppMain.set_help_all_flag("--help-all", "Print full help message and exit");
|
||||
AppMain.footer("Partition Manager Tool is written by YZBruh\n"
|
||||
"This project licensed under "
|
||||
"Apache 2.0 license\nReport "
|
||||
"bugs to https://github.com/ShawkTeam/pmt-renovated/issues");
|
||||
AppMain
|
||||
.add_option("-S,--search-path", VARS.searchPath,
|
||||
"Set partition search path")
|
||||
->check([&](const std::string &val) {
|
||||
if (val.find("/block") == std::string::npos)
|
||||
return std::string(
|
||||
"Partition search path is unexpected! Couldn't find "
|
||||
"'block' in input path!");
|
||||
return std::string();
|
||||
});
|
||||
AppMain.add_option("-L,--log-file", VARS.logFile, "Set log file");
|
||||
AppMain.add_flag("-f,--force", VARS.forceProcess,
|
||||
"Force process to be processed");
|
||||
AppMain.add_flag("-l,--logical", VARS.onLogical,
|
||||
"Specify that the target partition is dynamic");
|
||||
AppMain.add_flag("-q,--quiet", VARS.quietProcess, "Quiet process");
|
||||
AppMain.add_flag("-V,--verbose", VARS.verboseMode,
|
||||
"Detailed information is written on the screen while the "
|
||||
"transaction is "
|
||||
"being carried out");
|
||||
AppMain.add_flag("-v,--version", VARS.viewVersion,
|
||||
"Print version and exit");
|
||||
|
||||
REGISTER_FUNCTION(backupFunction);
|
||||
REGISTER_FUNCTION(cleanLogFunction);
|
||||
REGISTER_FUNCTION(flashFunction);
|
||||
REGISTER_FUNCTION(eraseFunction);
|
||||
REGISTER_FUNCTION(partitionSizeFunction);
|
||||
REGISTER_FUNCTION(infoFunction);
|
||||
REGISTER_FUNCTION(realPathFunction);
|
||||
REGISTER_FUNCTION(typeFunction);
|
||||
REGISTER_FUNCTION(rebootFunction);
|
||||
REGISTER_FUNCTION(memoryTestFunction);
|
||||
|
||||
CLI11_PARSE(AppMain, argc, argv);
|
||||
|
||||
if (Variables->verboseMode) Helper::LoggingProperties::setPrinting(YES);
|
||||
if (Variables->viewVersion) {
|
||||
if (VARS.verboseMode) Helper::LoggingProperties::setPrinting<YES>();
|
||||
if (VARS.viewVersion) {
|
||||
println("%s", getAppVersion().data());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (!Variables->searchPath.empty())
|
||||
(*Variables->PartMap)(Variables->searchPath);
|
||||
|
||||
if (!Variables->PartMap && Variables->searchPath.empty())
|
||||
throw Error("No default search entries were found. Specify a search "
|
||||
"directory with -S "
|
||||
"(--search-path)");
|
||||
if (FuncManager.hasFlagOnUsedFunction(NO_MAP_CHECK)) {
|
||||
if (!VARS.searchPath.empty())
|
||||
WARNING("-S (--search-path) flag is ignored. Because, don't needed "
|
||||
"partition map by your used function.\n");
|
||||
if (VARS.onLogical)
|
||||
WARNING("-l (--logical) flag ignored. Because, partition type don't "
|
||||
"needed by your used function.\n");
|
||||
} else {
|
||||
if (!VARS.searchPath.empty()) (PART_MAP)(VARS.searchPath);
|
||||
if (!VARS.PartMap && VARS.searchPath.empty())
|
||||
throw Error("No default search entries were found. Specify a search "
|
||||
"directory with -S "
|
||||
"(--search-path)");
|
||||
|
||||
if (!Helper::hasSuperUser()) {
|
||||
if (!(FuncManager.isUsed("rebootFunction") && Helper::hasAdbPermissions()))
|
||||
throw Error(
|
||||
"Partition Manager Tool is requires super-user privileges!\n");
|
||||
if (VARS.onLogical) {
|
||||
if (!PART_MAP.hasLogicalPartitions())
|
||||
throw Error(
|
||||
"This device doesn't contains logical partitions. But you "
|
||||
"used -l (--logical) flag.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Helper::hasSuperUser() && !FuncManager.hasFlagOnUsedFunction(NO_SU)) {
|
||||
if (!(FuncManager.hasFlagOnUsedFunction(ADB_SUFFICIENT) &&
|
||||
Helper::hasAdbPermissions())) {
|
||||
throw Error("This function is requires super-user privileges!");
|
||||
}
|
||||
}
|
||||
|
||||
return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
} catch (Helper::Error &error) {
|
||||
// catch Helper::Error
|
||||
|
||||
if (!Variables->quietProcess)
|
||||
fprintf(stderr, "%s%sERROR(S) OCCURRED:%s\n%s", RED, BOLD, STYLE_RESET,
|
||||
error.what());
|
||||
fprintf(pstderr, "%s%sERROR(S) OCCURRED:%s\n%s\n", RED, BOLD, STYLE_RESET,
|
||||
error.what());
|
||||
return EXIT_FAILURE;
|
||||
} catch (CLI::Error &error) {
|
||||
// catch CLI::Error
|
||||
@@ -140,29 +205,18 @@ int Main(int argc, char **argv) {
|
||||
void print(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (!Variables->quietProcess) vfprintf(stdout, format, args);
|
||||
vfprintf(pstdout, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void println(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (!Variables->quietProcess) {
|
||||
vfprintf(stdout, format, args);
|
||||
print("\n");
|
||||
}
|
||||
vfprintf(pstdout, format, args);
|
||||
print("\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
std::string format(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
char str[1024];
|
||||
vsnprintf(str, sizeof(str), format, args);
|
||||
va_end(args);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string getLibVersion() { MKVERSION(PMT); }
|
||||
|
||||
std::string getAppVersion() { MKVERSION(PMTE); }
|
||||
|
||||
@@ -25,35 +25,36 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#define BFUN "backupFunction"
|
||||
#define FUNCTION_CLASS backupFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
pair backupFunction::runAsync(const std::string &partitionName,
|
||||
const std::string &outputName, int bufferSize) {
|
||||
if (!Variables->PartMap->hasPartition(partitionName))
|
||||
return {format("Couldn't find partition: %s", partitionName.data()), false};
|
||||
RUN_ASYNC(const std::string &partitionName, const std::string &outputName,
|
||||
const uint64_t bufferSize) {
|
||||
if (!PART_MAP.hasPartition(partitionName))
|
||||
return {Helper::format("Couldn't find partition: %s", partitionName.data()),
|
||||
false};
|
||||
|
||||
LOGN(BFUN, INFO) << "back upping " << partitionName << " as " << outputName
|
||||
LOGN(BFUN, INFO) << "Back upping " << partitionName << " as " << outputName
|
||||
<< std::endl;
|
||||
|
||||
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
|
||||
if (Variables->forceProcess)
|
||||
if (VARS.onLogical && !PART_MAP.isLogical(partitionName)) {
|
||||
if (VARS.forceProcess)
|
||||
LOGN(BFUN, WARNING)
|
||||
<< "Partition " << partitionName
|
||||
<< " is exists but not logical. Ignoring (from --force, -f)."
|
||||
<< std::endl;
|
||||
else
|
||||
return {
|
||||
format("Used --logical (-l) flag but is not logical partition: %s",
|
||||
partitionName.data()),
|
||||
false};
|
||||
return {Helper::format(
|
||||
"Used --logical (-l) flag but is not logical partition: %s",
|
||||
partitionName.data()),
|
||||
false};
|
||||
}
|
||||
|
||||
if (Helper::fileIsExists(outputName) && !Variables->forceProcess)
|
||||
return {format("%s is exists. Remove it, or use --force (-f) flag.",
|
||||
outputName.data()),
|
||||
if (Helper::fileIsExists(outputName) && !VARS.forceProcess)
|
||||
return {Helper::format("%s is exists. Remove it, or use --force (-f) flag.",
|
||||
outputName.data()),
|
||||
false};
|
||||
|
||||
setupBufferSize(bufferSize, partitionName);
|
||||
LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName
|
||||
<< "): " << bufferSize << std::endl;
|
||||
|
||||
@@ -61,22 +62,22 @@ pair backupFunction::runAsync(const std::string &partitionName,
|
||||
Helper::garbageCollector collector;
|
||||
|
||||
const int pfd = Helper::openAndAddToCloseList(
|
||||
Variables->PartMap->getRealPathOf(partitionName), collector, O_RDONLY);
|
||||
PART_MAP.getRealPathOf(partitionName), collector, O_RDONLY);
|
||||
if (pfd < 0)
|
||||
return {format("Can't open partition: %s: %s", partitionName.data(),
|
||||
strerror(errno)),
|
||||
return {Helper::format("Can't open partition: %s: %s", partitionName.data(),
|
||||
strerror(errno)),
|
||||
false};
|
||||
|
||||
const int ffd = Helper::openAndAddToCloseList(
|
||||
outputName, collector, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (ffd < 0)
|
||||
return {format("Can't create/open output file %s: %s", outputName.data(),
|
||||
strerror(errno)),
|
||||
return {Helper::format("Can't create/open output file %s: %s",
|
||||
outputName.data(), strerror(errno)),
|
||||
false};
|
||||
|
||||
LOGN(BFUN, INFO) << "Writing partition " << partitionName
|
||||
<< " to file: " << outputName << std::endl;
|
||||
auto *buffer = new char[bufferSize];
|
||||
auto *buffer = new (std::nothrow) char[bufferSize];
|
||||
collector.delAfterProgress(buffer);
|
||||
memset(buffer, 0x00, bufferSize);
|
||||
|
||||
@@ -84,8 +85,8 @@ pair backupFunction::runAsync(const std::string &partitionName,
|
||||
while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) {
|
||||
if (const ssize_t bytesWritten = write(ffd, buffer, bytesRead);
|
||||
bytesWritten != bytesRead)
|
||||
return {format("Can't write partition to output file %s: %s",
|
||||
outputName.data(), strerror(errno)),
|
||||
return {Helper::format("Can't write partition to output file %s: %s",
|
||||
outputName.data(), strerror(errno)),
|
||||
false};
|
||||
}
|
||||
|
||||
@@ -94,18 +95,18 @@ pair backupFunction::runAsync(const std::string &partitionName,
|
||||
<< outputName
|
||||
<< ". Access problems maybe occur in non-root mode"
|
||||
<< std::endl;
|
||||
if (!Helper::changeMode(outputName, 0660))
|
||||
if (!Helper::changeMode(outputName, 0664))
|
||||
LOGN(BFUN, WARNING) << "Failed to change mode of output file as 660: "
|
||||
<< outputName
|
||||
<< ". Access problems maybe occur in non-root mode"
|
||||
<< std::endl;
|
||||
|
||||
return {format("%s partition successfully back upped to %s",
|
||||
partitionName.data(), outputName.data()),
|
||||
return {Helper::format("%s partition successfully back upped to %s",
|
||||
partitionName.data(), outputName.data()),
|
||||
true};
|
||||
}
|
||||
|
||||
bool backupFunction::init(CLI::App &_app) {
|
||||
INIT {
|
||||
LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl;
|
||||
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
|
||||
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")
|
||||
@@ -115,14 +116,15 @@ bool backupFunction::init(CLI::App &_app) {
|
||||
cmd->add_option("-O,--output-directory", outputDirectory,
|
||||
"Directory to save the partition image(s)")
|
||||
->check(CLI::ExistingDirectory);
|
||||
cmd->add_option(
|
||||
"-b,--buffer-size", bufferSize,
|
||||
"Buffer size for reading partition(s) and writing to file(s)");
|
||||
cmd->add_option("-b,--buffer-size", bufferSize,
|
||||
"Buffer size for reading partition(s) and writing to file(s)")
|
||||
->transform(CLI::AsSizeValue(false))
|
||||
->default_val("4KB");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool backupFunction::run() {
|
||||
RUN {
|
||||
processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames,
|
||||
',', true);
|
||||
if (!outputNames.empty() && partitions.size() != outputNames.size())
|
||||
@@ -131,13 +133,15 @@ bool backupFunction::run() {
|
||||
|
||||
std::vector<std::future<pair>> futures;
|
||||
for (size_t i = 0; i < partitions.size(); i++) {
|
||||
uint64_t buf = bufferSize;
|
||||
std::string partitionName = partitions[i];
|
||||
std::string outputName =
|
||||
outputNames.empty() ? partitionName + ".img" : outputNames[i];
|
||||
if (!outputDirectory.empty()) outputName.insert(0, outputDirectory + '/');
|
||||
|
||||
setupBufferSize(buf, partitionName);
|
||||
futures.push_back(std::async(std::launch::async, runAsync, partitionName,
|
||||
outputName, bufferSize));
|
||||
outputName, buf));
|
||||
LOGN(BFUN, INFO) << "Created thread backup upping " << partitionName
|
||||
<< std::endl;
|
||||
}
|
||||
@@ -158,7 +162,7 @@ bool backupFunction::run() {
|
||||
return endResult;
|
||||
}
|
||||
|
||||
bool backupFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *backupFunction::name() const { return BFUN; }
|
||||
NAME { return BFUN; }
|
||||
} // namespace PartitionManager
|
||||
|
||||
42
src/functions/CleanLogFunction.cpp
Normal file
42
src/functions/CleanLogFunction.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright 2025 Yağız Zengin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "functions.hpp"
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
|
||||
#define CFUN "cleanLogFunction"
|
||||
#define FUNCTION_CLASS cleanLogFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
INIT {
|
||||
LOGN(CFUN, INFO) << "Initializing variables of clean log function."
|
||||
<< std::endl;
|
||||
flags = {FunctionFlags::NO_MAP_CHECK, FunctionFlags::NO_SU};
|
||||
cmd = _app.add_subcommand("clean-logs", "Clean PMT logs.");
|
||||
return true;
|
||||
}
|
||||
|
||||
RUN {
|
||||
LOGN(CFUN, INFO) << "Removing log file: " << VARS.logFile << std::endl;
|
||||
Helper::LoggingProperties::setLoggingState<YES>(); // eraseEntry writes log!
|
||||
return Helper::eraseEntry(VARS.logFile);
|
||||
}
|
||||
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
NAME { return CFUN; }
|
||||
|
||||
} // namespace PartitionManager
|
||||
@@ -17,58 +17,60 @@ Copyright 2025 Yağız Zengin
|
||||
#include "functions.hpp"
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <fcntl.h>
|
||||
#include <future>
|
||||
#include <unistd.h>
|
||||
|
||||
#define EFUN "eraseFunction"
|
||||
#define FUNCTION_CLASS eraseFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
|
||||
if (!Variables->PartMap->hasPartition(partitionName))
|
||||
return {format("Couldn't find partition: %s", partitionName.data()), false};
|
||||
RUN_ASYNC(const std::string &partitionName, const uint64_t bufferSize) {
|
||||
if (!PART_MAP.hasPartition(partitionName))
|
||||
return {Helper::format("Couldn't find partition: %s", partitionName.data()),
|
||||
false};
|
||||
|
||||
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
|
||||
if (Variables->forceProcess)
|
||||
if (VARS.onLogical && !PART_MAP.isLogical(partitionName)) {
|
||||
if (VARS.forceProcess)
|
||||
LOGN(EFUN, WARNING)
|
||||
<< "Partition " << partitionName
|
||||
<< " is exists but not logical. Ignoring (from --force, -f)."
|
||||
<< std::endl;
|
||||
else
|
||||
return {
|
||||
format("Used --logical (-l) flag but is not logical partition: %s",
|
||||
partitionName.data()),
|
||||
false};
|
||||
return {Helper::format(
|
||||
"Used --logical (-l) flag but is not logical partition: %s",
|
||||
partitionName.data()),
|
||||
false};
|
||||
}
|
||||
|
||||
setupBufferSize(bufferSize, partitionName);
|
||||
LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize;
|
||||
|
||||
// Automatically close file descriptors and delete allocated memories (arrays)
|
||||
Helper::garbageCollector collector;
|
||||
|
||||
const int pfd = Helper::openAndAddToCloseList(
|
||||
Variables->PartMap->getRealPathOf(partitionName), collector, O_WRONLY);
|
||||
PART_MAP.getRealPathOf(partitionName), collector, O_WRONLY);
|
||||
if (pfd < 0)
|
||||
return {format("Can't open partition: %s: %s", partitionName.data(),
|
||||
strerror(errno)),
|
||||
return {Helper::format("Can't open partition: %s: %s", partitionName.data(),
|
||||
strerror(errno)),
|
||||
false};
|
||||
|
||||
if (!Variables->forceProcess)
|
||||
Helper::confirmPropt(
|
||||
"Are you sure you want to continue? This could render your device "
|
||||
"unusable! Do not continue if you "
|
||||
"do not know what you are doing!");
|
||||
if (!VARS.forceProcess) {
|
||||
if (!Helper::confirmPropt(
|
||||
"Are you sure you want to continue? This could render your device "
|
||||
"unusable! Do not continue if you "
|
||||
"do not know what you are doing!"))
|
||||
throw Error("Operation canceled.");
|
||||
}
|
||||
|
||||
LOGN(EFUN, INFO) << "Writing zero bytes to partition: " << partitionName
|
||||
<< std::endl;
|
||||
auto *buffer = new char[bufferSize];
|
||||
auto *buffer = new (std::nothrow) char[bufferSize];
|
||||
collector.delAfterProgress(buffer);
|
||||
memset(buffer, 0x00, bufferSize);
|
||||
|
||||
ssize_t bytesWritten = 0;
|
||||
const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName);
|
||||
const uint64_t partitionSize = PART_MAP.sizeOf(partitionName);
|
||||
|
||||
while (bytesWritten < partitionSize) {
|
||||
size_t toWrite = sizeof(buffer);
|
||||
@@ -76,33 +78,37 @@ pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
|
||||
toWrite = partitionSize - bytesWritten;
|
||||
|
||||
if (const ssize_t result = write(pfd, buffer, toWrite); result == -1)
|
||||
return {format("Can't write zero bytes to partition: %s: %s",
|
||||
partitionName.data(), strerror(errno)),
|
||||
return {Helper::format("Can't write zero bytes to partition: %s: %s",
|
||||
partitionName.data(), strerror(errno)),
|
||||
false};
|
||||
else bytesWritten += result;
|
||||
}
|
||||
|
||||
return {format("Successfully wrote zero bytes to the %s partition\n",
|
||||
partitionName.data()),
|
||||
return {Helper::format("Successfully wrote zero bytes to the %s partition",
|
||||
partitionName.data()),
|
||||
true};
|
||||
}
|
||||
|
||||
bool eraseFunction::init(CLI::App &_app) {
|
||||
INIT {
|
||||
LOGN(EFUN, INFO) << "Initializing variables of erase function." << std::endl;
|
||||
cmd = _app.add_subcommand("erase", "Writes zero bytes to partition(s)");
|
||||
cmd->add_option("partition(s)", partitions, "Partition name(s)")
|
||||
->required()
|
||||
->delimiter(',');
|
||||
cmd->add_option("-b,--buffer-size", bufferSize,
|
||||
"Buffer size for writing zero bytes to partition(s)");
|
||||
"Buffer size for writing zero bytes to partition(s)")
|
||||
->transform(CLI::AsSizeValue(false))
|
||||
->default_val("4KB");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eraseFunction::run() {
|
||||
RUN {
|
||||
std::vector<std::future<pair>> futures;
|
||||
for (const auto &partitionName : partitions) {
|
||||
uint64_t buf = bufferSize;
|
||||
setupBufferSize(buf, partitionName);
|
||||
futures.push_back(
|
||||
std::async(std::launch::async, runAsync, partitionName, bufferSize));
|
||||
std::async(std::launch::async, runAsync, partitionName, buf));
|
||||
LOGN(EFUN, INFO) << "Created thread for writing zero bytes to "
|
||||
<< partitionName << std::endl;
|
||||
}
|
||||
@@ -123,7 +129,7 @@ bool eraseFunction::run() {
|
||||
return endResult;
|
||||
}
|
||||
|
||||
bool eraseFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *eraseFunction::name() const { return EFUN; }
|
||||
NAME { return EFUN; }
|
||||
} // namespace PartitionManager
|
||||
|
||||
@@ -23,58 +23,59 @@ Copyright 2025 Yağız Zengin
|
||||
#include <unistd.h>
|
||||
|
||||
#define FFUN "flashFunction"
|
||||
#define FUNCTION_CLASS flashFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
pair flashFunction::runAsync(const std::string &partitionName,
|
||||
const std::string &imageName, int bufferSize) {
|
||||
RUN_ASYNC(const std::string &partitionName, const std::string &imageName,
|
||||
const uint64_t bufferSize, const bool deleteAfterProgress) {
|
||||
if (!Helper::fileIsExists(imageName))
|
||||
return {format("Couldn't find image file: %s", imageName.data()), false};
|
||||
if (!Variables->PartMap->hasPartition(partitionName))
|
||||
return {format("Couldn't find partition: %s", partitionName.data()), false};
|
||||
if (Helper::fileSize(imageName) > Variables->PartMap->sizeOf(partitionName))
|
||||
return {format("%s is larger than %s partition size!", imageName.data(),
|
||||
partitionName.data()),
|
||||
return {Helper::format("Couldn't find image file: %s", imageName.data()),
|
||||
false};
|
||||
if (!PART_MAP.hasPartition(partitionName))
|
||||
return {Helper::format("Couldn't find partition: %s", partitionName.data()),
|
||||
false};
|
||||
if (Helper::fileSize(imageName) > PART_MAP.sizeOf(partitionName))
|
||||
return {Helper::format("%s is larger than %s partition size!",
|
||||
imageName.data(), partitionName.data()),
|
||||
false};
|
||||
|
||||
LOGN(FFUN, INFO) << "flashing " << imageName << " to " << partitionName
|
||||
<< std::endl;
|
||||
|
||||
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
|
||||
if (Variables->forceProcess)
|
||||
if (VARS.onLogical && !PART_MAP.isLogical(partitionName)) {
|
||||
if (VARS.forceProcess)
|
||||
LOGN(FFUN, WARNING)
|
||||
<< "Partition " << partitionName
|
||||
<< " is exists but not logical. Ignoring (from --force, -f)."
|
||||
<< std::endl;
|
||||
else
|
||||
return {
|
||||
format("Used --logical (-l) flag but is not logical partition: %s",
|
||||
partitionName.data()),
|
||||
false};
|
||||
return {Helper::format(
|
||||
"Used --logical (-l) flag but is not logical partition: %s",
|
||||
partitionName.data()),
|
||||
false};
|
||||
}
|
||||
|
||||
setupBufferSize(bufferSize, imageName);
|
||||
LOGN(FFUN, INFO) << "Using buffer size: " << bufferSize;
|
||||
LOGN(FFUN, INFO) << "Using buffer size: " << bufferSize << std::endl;
|
||||
|
||||
// Automatically close file descriptors and delete allocated memories (arrays)
|
||||
Helper::garbageCollector collector;
|
||||
|
||||
const int ffd = Helper::openAndAddToCloseList(imageName, collector, O_RDONLY);
|
||||
if (ffd < 0)
|
||||
return {format("Can't open image file %s: %s", imageName.data(),
|
||||
strerror(errno)),
|
||||
return {Helper::format("Can't open image file %s: %s", imageName.data(),
|
||||
strerror(errno)),
|
||||
false};
|
||||
|
||||
const int pfd = Helper::openAndAddToCloseList(
|
||||
Variables->PartMap->getRealPathOf(partitionName), collector,
|
||||
O_RDWR | O_TRUNC);
|
||||
PART_MAP.getRealPathOf(partitionName), collector, O_RDWR | O_TRUNC);
|
||||
if (pfd < 0)
|
||||
return {format("Can't open partition: %s: %s", partitionName.data(),
|
||||
strerror(errno)),
|
||||
return {Helper::format("Can't open partition: %s: %s", partitionName.data(),
|
||||
strerror(errno)),
|
||||
false};
|
||||
|
||||
LOGN(FFUN, INFO) << "Writing image " << imageName
|
||||
<< " to partition: " << partitionName << std::endl;
|
||||
auto *buffer = new char[bufferSize];
|
||||
auto *buffer = new (std::nothrow) char[bufferSize];
|
||||
collector.delAfterProgress(buffer);
|
||||
memset(buffer, 0x00, bufferSize);
|
||||
|
||||
@@ -82,17 +83,24 @@ pair flashFunction::runAsync(const std::string &partitionName,
|
||||
while ((bytesRead = read(ffd, buffer, bufferSize)) > 0) {
|
||||
if (const ssize_t bytesWritten = write(pfd, buffer, bytesRead);
|
||||
bytesWritten != bytesRead)
|
||||
return {format("Can't write partition to output file %s: %s",
|
||||
imageName.data(), strerror(errno)),
|
||||
return {Helper::format("Can't write partition to output file %s: %s",
|
||||
imageName.data(), strerror(errno)),
|
||||
false};
|
||||
}
|
||||
|
||||
return {format("%s is successfully wrote to %s partition", imageName.data(),
|
||||
partitionName.data()),
|
||||
if (deleteAfterProgress) {
|
||||
LOGN(FFUN, INFO) << "Deleting flash file: " << imageName << std::endl;
|
||||
if (!Helper::eraseEntry(imageName) && !VARS.quietProcess)
|
||||
WARNING(
|
||||
std::string("Cannot erase flash file: " + imageName + "\n").data());
|
||||
}
|
||||
|
||||
return {Helper::format("%s is successfully wrote to %s partition",
|
||||
imageName.data(), partitionName.data()),
|
||||
true};
|
||||
}
|
||||
|
||||
bool flashFunction::init(CLI::App &_app) {
|
||||
INIT {
|
||||
LOGN(FFUN, INFO) << "Initializing variables of flash function." << std::endl;
|
||||
cmd = _app.add_subcommand("flash", "Flash image(s) to partition(s)");
|
||||
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")
|
||||
@@ -100,28 +108,38 @@ bool flashFunction::init(CLI::App &_app) {
|
||||
cmd->add_option("imageFile(s)", rawImageNames, "Name(s) of image file(s)")
|
||||
->required();
|
||||
cmd->add_option(
|
||||
"-b,--buffer-size", bufferSize,
|
||||
"Buffer size for reading image(s) and writing to partition(s)");
|
||||
"-b,--buffer-size", bufferSize,
|
||||
"Buffer size for reading image(s) and writing to partition(s)")
|
||||
->transform(CLI::AsSizeValue(false))
|
||||
->default_val("4KB");
|
||||
cmd->add_option("-I,--image-directory", imageDirectory,
|
||||
"Directory to find image(s) and flash to partition(s)");
|
||||
cmd->add_flag("-d,--delete", deleteAfterProgress,
|
||||
"Delete flash file(s) after progress.")
|
||||
->default_val(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flashFunction::run() {
|
||||
RUN {
|
||||
processCommandLine(partitions, imageNames, rawPartitions, rawImageNames, ',',
|
||||
true);
|
||||
if (partitions.size() != imageNames.size())
|
||||
throw CLI::ValidationError(
|
||||
"You must provide an image file(s) as long as the partition name(s)");
|
||||
|
||||
for (size_t i = 0; i < partitions.size(); i++) {
|
||||
if (!imageDirectory.empty()) imageNames[i].insert(0, imageDirectory + '/');
|
||||
}
|
||||
|
||||
std::vector<std::future<pair>> futures;
|
||||
for (size_t i = 0; i < partitions.size(); i++) {
|
||||
std::string imageName = imageNames[i];
|
||||
if (!imageDirectory.empty()) imageName.insert(0, imageDirectory + '/');
|
||||
uint64_t buf = bufferSize;
|
||||
|
||||
setupBufferSize(buf, imageNames[i]);
|
||||
futures.push_back(std::async(std::launch::async, runAsync, partitions[i],
|
||||
imageName, bufferSize));
|
||||
imageNames[i], bufferSize,
|
||||
deleteAfterProgress));
|
||||
LOGN(FFUN, INFO) << "Created thread for flashing image to " << partitions[i]
|
||||
<< std::endl;
|
||||
}
|
||||
@@ -142,7 +160,7 @@ bool flashFunction::run() {
|
||||
return endResult;
|
||||
}
|
||||
|
||||
bool flashFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *flashFunction::name() const { return FFUN; }
|
||||
NAME { return FFUN; }
|
||||
} // namespace PartitionManager
|
||||
|
||||
@@ -19,52 +19,62 @@ Copyright 2025 Yağız Zengin
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define IFUN "infoFunction"
|
||||
#define FUNCTION_CLASS infoFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
bool infoFunction::init(CLI::App &_app) {
|
||||
|
||||
INIT {
|
||||
LOGN(IFUN, INFO) << "Initializing variables of info printer function."
|
||||
<< std::endl;
|
||||
cmd = _app.add_subcommand("info", "Tell info(s) of input partition list")
|
||||
->footer("Use get-all or getvar-all as partition name for getting "
|
||||
"info's of all "
|
||||
"partitions.");
|
||||
"info's of all partitions.\nUse get-logicals as partition "
|
||||
"name for getting info's of logical partitions.\n"
|
||||
"Use get-physical as partition name for getting info's of "
|
||||
"physical partitions.");
|
||||
cmd->add_option("partition(s)", partitions, "Partition name(s).")
|
||||
->required()
|
||||
->delimiter(',');
|
||||
cmd->add_flag("-J,--json", jsonFormat,
|
||||
"Print info(s) as JSON body. The body of each partition will "
|
||||
"be written separately");
|
||||
"be written separately")
|
||||
->default_val(false);
|
||||
cmd->add_flag("--as-byte", asByte, "View sizes as byte.")->default_val(true);
|
||||
cmd->add_flag("--as-kilobyte", asKiloBytes, "View sizes as kilobyte.")
|
||||
->default_val(false);
|
||||
cmd->add_flag("--as-megabyte", asMega, "View sizes as megabyte.")
|
||||
->default_val(false);
|
||||
cmd->add_flag("--as-gigabyte", asGiga, "View sizes as gigabyte.")
|
||||
->default_val(false);
|
||||
cmd->add_option("--json-partition-name", jNamePartition,
|
||||
"Speficy partition name element for JSON body");
|
||||
"Specify partition name element for JSON body")
|
||||
->default_val("name");
|
||||
cmd->add_option("--json-size-name", jNameSize,
|
||||
"Speficy size element name for JSON body");
|
||||
"Specify size element name for JSON body")
|
||||
->default_val("size");
|
||||
cmd->add_option("--json-logical-name", jNameLogical,
|
||||
"Speficy logical element name for JSON body");
|
||||
"Specify logical element name for JSON body")
|
||||
->default_val("isLogical");
|
||||
cmd->add_option("--json-indent-size", jIndentSize,
|
||||
"Set JSON indent size for printing to screen")
|
||||
->default_val(2);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool infoFunction::run() {
|
||||
if (partitions.back() == "get-all" || partitions.back() == "getvar-all") {
|
||||
partitions.clear();
|
||||
const auto parts = Variables->PartMap->getPartitionList();
|
||||
if (!parts)
|
||||
throw Error("Cannot get list of all partitions! See logs for more "
|
||||
"information (%s)",
|
||||
Helper::LoggingProperties::FILE.data());
|
||||
RUN {
|
||||
std::vector<PartitionMap::Partition_t> jParts;
|
||||
sizeCastTypes multiple;
|
||||
if (asByte) multiple = B;
|
||||
if (asKiloBytes) multiple = KB;
|
||||
if (asMega) multiple = MB;
|
||||
if (asGiga) multiple = GB;
|
||||
|
||||
for (const auto &name : *parts)
|
||||
partitions.push_back(name);
|
||||
}
|
||||
|
||||
for (const auto &partition : partitions) {
|
||||
if (!Variables->PartMap->hasPartition(partition))
|
||||
throw Error("Couldn't find partition: %s", partition.data());
|
||||
|
||||
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
|
||||
if (Variables->forceProcess)
|
||||
auto func = [this, &jParts, &multiple] COMMON_LAMBDA_PARAMS -> bool {
|
||||
if (VARS.onLogical && !props.isLogical) {
|
||||
if (VARS.forceProcess)
|
||||
LOGN(IFUN, WARNING)
|
||||
<< "Partition " << partition
|
||||
<< " is exists but not logical. Ignoring (from --force, -f)."
|
||||
@@ -75,28 +85,43 @@ bool infoFunction::run() {
|
||||
}
|
||||
|
||||
if (jsonFormat)
|
||||
#ifdef __LP64__
|
||||
println("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}",
|
||||
#else
|
||||
println("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}",
|
||||
#endif
|
||||
jNamePartition.data(), partition.data(), jNameSize.data(),
|
||||
Variables->PartMap->sizeOf(partition), jNameLogical.data(),
|
||||
Variables->PartMap->isLogical(partition) ? "true" : "false");
|
||||
jParts.push_back(
|
||||
{partition,
|
||||
{static_cast<uint64_t>(Helper::convertTo(props.size, multiple)),
|
||||
props.isLogical}});
|
||||
else
|
||||
#ifdef __LP64__
|
||||
println("partition=%s size=%lu isLogical=%s",
|
||||
#else
|
||||
println("partition=%s size=%llu isLogical=%s",
|
||||
#endif
|
||||
partition.data(), Variables->PartMap->sizeOf(partition),
|
||||
Variables->PartMap->isLogical(partition) ? "true" : "false");
|
||||
println("partition=%s size=%d isLogical=%s", partition.data(),
|
||||
Helper::convertTo(props.size, multiple),
|
||||
props.isLogical ? "true" : "false");
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (partitions.back() == "get-all" || partitions.back() == "getvar-all")
|
||||
PART_MAP.doForAllPartitions(func);
|
||||
else if (partitions.back() == "get-logicals")
|
||||
PART_MAP.doForLogicalPartitions(func);
|
||||
else if (partitions.back() == "get-physicals")
|
||||
PART_MAP.doForPhysicalPartitions(func);
|
||||
else PART_MAP.doForPartitionList(partitions, func);
|
||||
|
||||
if (jsonFormat) {
|
||||
nlohmann::json j;
|
||||
j["multipleType"] = Helper::multipleToString(multiple);
|
||||
j["partitions"] = nlohmann::json::array();
|
||||
for (const auto &[name, props] : jParts) {
|
||||
j["partitions"].push_back({{jNamePartition, name},
|
||||
{jNameSize, props.size},
|
||||
{jNameLogical, props.isLogical}});
|
||||
}
|
||||
|
||||
println("%s", j.dump(jIndentSize).data());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool infoFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *infoFunction::name() const { return IFUN; };
|
||||
NAME { return IFUN; };
|
||||
} // namespace PartitionManager
|
||||
|
||||
132
src/functions/MemoryTestFunction.cpp
Normal file
132
src/functions/MemoryTestFunction.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
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 "functions.hpp"
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <random>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MTFUN "memoryTestFunction"
|
||||
#define FUNCTION_CLASS memoryTestFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
|
||||
INIT {
|
||||
LOGN(MTFUN, INFO) << "Initializing variables of memory test function."
|
||||
<< std::endl;
|
||||
flags = {FunctionFlags::NO_MAP_CHECK, FunctionFlags::ADB_SUFFICIENT};
|
||||
cmd = _app.add_subcommand("memtest", "Test your write/read speed of device.");
|
||||
cmd->add_option("testDirectory", testPath, "Path to test directory")
|
||||
->default_val("/data/local/tmp")
|
||||
->check([&](const std::string &val) {
|
||||
if (val.find("/sdcard") != std::string::npos ||
|
||||
val.find("/storage") != std::string::npos)
|
||||
return std::string(
|
||||
"Sequential read tests on FUSE-mounted paths do not give correct "
|
||||
"results, so its use is prohibited (by pmt)!");
|
||||
|
||||
if (val != "/data/local/tmp" && !Helper::directoryIsExists(val))
|
||||
return std::string("Couldn't find directory: " + val +
|
||||
", no root? Try executing in ADB shell.");
|
||||
|
||||
return std::string();
|
||||
});
|
||||
cmd->add_option("-s,--file-size", testFileSize, "File size of test file")
|
||||
->transform(CLI::AsSizeValue(false))
|
||||
->default_val("1GB");
|
||||
cmd->add_flag("--no-read-test", doNotReadTest,
|
||||
"Don't read test data from disk")
|
||||
->default_val(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RUN {
|
||||
if (testFileSize > GB(2) && !VARS.forceProcess)
|
||||
throw Error(
|
||||
"File size is more than 2GB! Sizes over 2GB may not give accurate "
|
||||
"results in the write test. Use -f (--force) for skip this error.");
|
||||
|
||||
LOGN(MTFUN, INFO) << "Starting memory test on " << testPath << std::endl;
|
||||
Helper::garbageCollector collector;
|
||||
const std::string test = Helper::pathJoin(testPath, "test.bin");
|
||||
|
||||
LOGN(MTFUN, INFO) << "Generating random data for testing" << std::endl;
|
||||
auto *buffer = new (std::nothrow) char[bufferSize];
|
||||
collector.delAfterProgress(buffer);
|
||||
|
||||
for (size_t i = 0; i < bufferSize; i++)
|
||||
buffer[i] = static_cast<char>(Helper::Random<1024>::getNumber());
|
||||
|
||||
collector.delFileAfterProgress(test);
|
||||
|
||||
const int wfd = Helper::openAndAddToCloseList(
|
||||
test, collector, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0644);
|
||||
if (wfd < 0) throw Error("Can't open/create test file: %s", strerror(errno));
|
||||
|
||||
LOGN(MTFUN, INFO) << "Sequential write test started!" << std::endl;
|
||||
const auto startWrite = std::chrono::high_resolution_clock::now();
|
||||
ssize_t bytesWritten = 0;
|
||||
while (bytesWritten < testFileSize) {
|
||||
const ssize_t ret = write(wfd, buffer, bufferSize);
|
||||
if (ret < 0) throw Error("Can't write to test file: %s", strerror(errno));
|
||||
bytesWritten += ret;
|
||||
}
|
||||
|
||||
const auto endWrite = std::chrono::high_resolution_clock::now();
|
||||
|
||||
const double writeTime =
|
||||
std::chrono::duration<double>(endWrite - startWrite).count();
|
||||
println("Sequential write speed: %3.f MB/s",
|
||||
(static_cast<double>(testFileSize) / (1024.0 * 1024.0)) / writeTime);
|
||||
LOGN(MTFUN, INFO) << "Sequential write test done!" << std::endl;
|
||||
|
||||
if (!doNotReadTest) {
|
||||
auto *rawBuffer = new char[bufferSize + 4096];
|
||||
collector.delAfterProgress(rawBuffer);
|
||||
auto *bufferRead = reinterpret_cast<char *>(
|
||||
(reinterpret_cast<uintptr_t>(rawBuffer) + 4096 - 1) & ~(4096 - 1));
|
||||
const int rfd =
|
||||
Helper::openAndAddToCloseList(test, collector, O_RDONLY | O_DIRECT);
|
||||
if (rfd < 0) throw Error("Can't open test file: %s", strerror(errno));
|
||||
|
||||
LOGN(MTFUN, INFO) << "Sequential read test started!" << std::endl;
|
||||
const auto startRead = std::chrono::high_resolution_clock::now();
|
||||
size_t total = 0;
|
||||
ssize_t bytesRead;
|
||||
while ((bytesRead = read(rfd, bufferRead, bufferSize)) > 0) {
|
||||
total += bytesRead;
|
||||
}
|
||||
const auto endRead = std::chrono::high_resolution_clock::now();
|
||||
|
||||
const double read_time =
|
||||
std::chrono::duration<double>(endRead - startRead).count();
|
||||
println("Sequential read speed: %3.f MB/s",
|
||||
(static_cast<double>(total) / (1024.0 * 1024.0)) / read_time);
|
||||
LOGN(MTFUN, INFO) << "Sequential read test done!" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
NAME { return MTFUN; }
|
||||
} // namespace PartitionManager
|
||||
@@ -18,44 +18,51 @@ Copyright 2025 Yağız Zengin
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
|
||||
#define SFUN "partitionSizeFunction"
|
||||
|
||||
std::string convertTo(const uint64_t size, const std::string &multiple) {
|
||||
if (multiple == "KB") return std::to_string(TO_KB(size));
|
||||
if (multiple == "MB") return std::to_string(TO_MB(size));
|
||||
if (multiple == "GB") return std::to_string(TO_GB(size));
|
||||
return std::to_string(size);
|
||||
}
|
||||
#define FUNCTION_CLASS partitionSizeFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
bool partitionSizeFunction::init(CLI::App &_app) {
|
||||
INIT {
|
||||
LOGN(SFUN, INFO)
|
||||
<< "Initializing variables of partition size getter function."
|
||||
<< std::endl;
|
||||
cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list");
|
||||
cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list")
|
||||
->footer("Use get-all or getvar-all as partition name for getting "
|
||||
"sizes of all partitions.\nUse get-logicals as partition "
|
||||
"name for getting sizes of logical partitions.\n"
|
||||
"Use get-physical as partition name for getting sizes of "
|
||||
"physical partitions.");
|
||||
cmd->add_option("partition(s)", partitions, "Partition name(s).")
|
||||
->required()
|
||||
->delimiter(',');
|
||||
cmd->add_flag("--as-byte", asByte,
|
||||
"Tell input size of partition list as byte.");
|
||||
"Tell input size of partition list as byte.")
|
||||
->default_val(false);
|
||||
cmd->add_flag("--as-kilobyte", asKiloBytes,
|
||||
"Tell input size of partition list as kilobyte.");
|
||||
"Tell input size of partition list as kilobyte.")
|
||||
->default_val(false);
|
||||
cmd->add_flag("--as-megabyte", asMega,
|
||||
"Tell input size of partition list as megabyte.");
|
||||
"Tell input size of partition list as megabyte.")
|
||||
->default_val(true);
|
||||
cmd->add_flag("--as-gigabyte", asGiga,
|
||||
"Tell input size of partition list as gigabyte.");
|
||||
"Tell input size of partition list as gigabyte.")
|
||||
->default_val(false);
|
||||
cmd->add_flag("--only-size", onlySize,
|
||||
"Tell input size of partition list as not printing multiple "
|
||||
"and partition name.");
|
||||
"and partition name.")
|
||||
->default_val(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool partitionSizeFunction::run() {
|
||||
for (const auto &partition : partitions) {
|
||||
if (!Variables->PartMap->hasPartition(partition))
|
||||
throw Error("Couldn't find partition: %s", partition.data());
|
||||
RUN {
|
||||
sizeCastTypes multiple = {};
|
||||
if (asByte) multiple = B;
|
||||
if (asKiloBytes) multiple = KB;
|
||||
if (asMega) multiple = MB;
|
||||
if (asGiga) multiple = GB;
|
||||
|
||||
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
|
||||
if (Variables->forceProcess)
|
||||
auto func = [this, &multiple] COMMON_LAMBDA_PARAMS -> bool {
|
||||
if (VARS.onLogical && !props.isLogical) {
|
||||
if (VARS.forceProcess)
|
||||
LOGN(SFUN, WARNING)
|
||||
<< "Partition " << partition
|
||||
<< " is exists but not logical. Ignoring (from --force, -f)."
|
||||
@@ -65,26 +72,27 @@ bool partitionSizeFunction::run() {
|
||||
partition.data());
|
||||
}
|
||||
|
||||
std::string multiple = "MB";
|
||||
if (asByte) multiple = "B";
|
||||
if (asKiloBytes) multiple = "KB";
|
||||
if (asMega) multiple = "MB";
|
||||
if (asGiga) multiple = "GB";
|
||||
|
||||
if (onlySize)
|
||||
println(
|
||||
"%s",
|
||||
convertTo(Variables->PartMap->sizeOf(partition), multiple).data());
|
||||
if (onlySize) println("%d", Helper::convertTo(props.size, multiple));
|
||||
else
|
||||
println("%s: %s%s", partition.data(),
|
||||
convertTo(Variables->PartMap->sizeOf(partition), multiple).data(),
|
||||
multiple.data());
|
||||
}
|
||||
println("%s: %d%s", partition.data(),
|
||||
Helper::convertTo(props.size, multiple),
|
||||
Helper::multipleToString(multiple).data());
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (partitions.back() == "get-all" || partitions.back() == "getvar-all")
|
||||
PART_MAP.doForAllPartitions(func);
|
||||
else if (partitions.back() == "get-logicals")
|
||||
PART_MAP.doForLogicalPartitions(func);
|
||||
else if (partitions.back() == "get-physicals")
|
||||
PART_MAP.doForPhysicalPartitions(func);
|
||||
else PART_MAP.doForPartitionList(partitions, func);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool partitionSizeFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *partitionSizeFunction::name() const { return SFUN; }
|
||||
NAME { return SFUN; }
|
||||
} // namespace PartitionManager
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
Copyright 2025 Yağız Zengin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "functions.hpp"
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
|
||||
#define RLPFUN "realPathFunction"
|
||||
|
||||
namespace PartitionManager {
|
||||
bool realLinkPathFunction::init(CLI::App &_app) {
|
||||
LOGN(RLPFUN, INFO) << "Initializing variables of real link path function."
|
||||
<< std::endl;
|
||||
cmd = _app.add_subcommand("real-linkpath",
|
||||
"Tell real link paths of partition(s)");
|
||||
cmd->add_option("partition(s)", partitions, "Partition name(s)")
|
||||
->required()
|
||||
->delimiter(',');
|
||||
return true;
|
||||
}
|
||||
|
||||
bool realLinkPathFunction::run() {
|
||||
for (const auto &partition : partitions) {
|
||||
if (!Variables->PartMap->hasPartition(partition))
|
||||
throw Error("Couldn't find partition: %s", partition.data());
|
||||
|
||||
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
|
||||
if (Variables->forceProcess)
|
||||
LOGN(RLPFUN, WARNING)
|
||||
<< "Partition " << partition
|
||||
<< " is exists but not logical. Ignoring (from --force, -f)."
|
||||
<< std::endl;
|
||||
else
|
||||
throw Error("Used --logical (-l) flag but is not logical partition: %s",
|
||||
partition.data());
|
||||
}
|
||||
|
||||
println("%s", Variables->PartMap->getRealPathOf(partition).data());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool realLinkPathFunction::isUsed() const { return cmd->parsed(); }
|
||||
|
||||
const char *realLinkPathFunction::name() const { return RLPFUN; }
|
||||
} // namespace PartitionManager
|
||||
@@ -18,25 +18,28 @@
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
|
||||
#define RPFUN "realPathFunction"
|
||||
#define FUNCTION_CLASS realPathFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
bool realPathFunction::init(CLI::App &_app) {
|
||||
INIT {
|
||||
LOGN(RPFUN, INFO) << "Initializing variables of real path function."
|
||||
<< std::endl;
|
||||
cmd = _app.add_subcommand("real-path", "Tell real paths of partition(s)");
|
||||
cmd->add_option("partition(s)", partitions, "Partition name(s)")
|
||||
->required()
|
||||
->delimiter(',');
|
||||
cmd->add_flag("--real-link-path", realLinkPath, "Print real link path(s)")
|
||||
->default_val(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool realPathFunction::run() {
|
||||
RUN {
|
||||
for (const auto &partition : partitions) {
|
||||
if (!Variables->PartMap->hasPartition(partition))
|
||||
if (!PART_MAP.hasPartition(partition))
|
||||
throw Error("Couldn't find partition: %s", partition.data());
|
||||
|
||||
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
|
||||
if (Variables->forceProcess)
|
||||
if (VARS.onLogical && !PART_MAP.isLogical(partition)) {
|
||||
if (VARS.forceProcess)
|
||||
LOGN(RPFUN, WARNING)
|
||||
<< "Partition " << partition
|
||||
<< " is exists but not logical. Ignoring (from --force, -f)."
|
||||
@@ -46,13 +49,15 @@ bool realPathFunction::run() {
|
||||
partition.data());
|
||||
}
|
||||
|
||||
println("%s", Variables->PartMap->getRealPathOf(partition).data());
|
||||
if (realLinkPath)
|
||||
println("%s", PART_MAP.getRealLinkPathOf(partition).data());
|
||||
else println("%s", PART_MAP.getRealPathOf(partition).data());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool realPathFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *realPathFunction::name() const { return RPFUN; }
|
||||
NAME { return RPFUN; }
|
||||
} // namespace PartitionManager
|
||||
|
||||
@@ -18,28 +18,30 @@ Copyright 2025 Yağız Zengin
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
|
||||
#define RFUN "rebootFunction"
|
||||
#define FUNCTION_CLASS rebootFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
bool rebootFunction::init(CLI::App &_app) {
|
||||
INIT {
|
||||
LOGN(RFUN, INFO) << "Initializing variables of reboot function." << std::endl;
|
||||
flags = {FunctionFlags::NO_MAP_CHECK, FunctionFlags::ADB_SUFFICIENT};
|
||||
cmd = _app.add_subcommand("reboot", "Reboots device");
|
||||
cmd->add_option("rebootTarget", rebootTarget,
|
||||
"Reboot target (default: normal)");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rebootFunction::run() {
|
||||
RUN {
|
||||
LOGN(RFUN, INFO) << "Rebooting device!!! (custom reboot target: "
|
||||
<< (rebootTarget.empty() ? "none" : rebootTarget)
|
||||
<< std::endl;
|
||||
|
||||
if (Helper::reboot(rebootTarget)) println("Reboot command was sent");
|
||||
if (Helper::androidReboot(rebootTarget)) println("Reboot command was sent");
|
||||
else throw Error("Cannot reboot device");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rebootFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *rebootFunction::name() const { return RFUN; }
|
||||
NAME { return RFUN; }
|
||||
} // namespace PartitionManager
|
||||
|
||||
@@ -16,27 +16,33 @@
|
||||
|
||||
#include "functions.hpp"
|
||||
#include <PartitionManager/PartitionManager.hpp>
|
||||
#include <map>
|
||||
|
||||
#define TFUN "typeFunction"
|
||||
#define FUNCTION_CLASS typeFunction
|
||||
|
||||
namespace PartitionManager {
|
||||
bool typeFunction::init(CLI::App &_app) {
|
||||
INIT {
|
||||
LOGN(TFUN, INFO) << "Initializing variables of type function." << std::endl;
|
||||
cmd = _app.add_subcommand("type", "Get type of the partition(s) or image(s)");
|
||||
cmd->add_option("content(s)", contents, "Content(s)")
|
||||
->required()
|
||||
->delimiter(',');
|
||||
cmd->add_option("-b,--buffer-size", bufferSize,
|
||||
"Buffer size for max seek depth");
|
||||
"Buffer size for max seek depth")
|
||||
->transform(CLI::AsSizeValue(false))
|
||||
->default_val("4KB");
|
||||
cmd->add_flag("--only-check-android-magics", onlyCheckAndroidMagics,
|
||||
"Only check Android magic values.");
|
||||
"Only check Android magic values.")
|
||||
->default_val(false);
|
||||
cmd->add_flag("--only-check-filesystem-magics", onlyCheckFileSystemMagics,
|
||||
"Only check filesystem magic values.");
|
||||
"Only check filesystem magic values.")
|
||||
->default_val(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool typeFunction::run() {
|
||||
std::unordered_map<uint64_t, std::string> magics;
|
||||
RUN {
|
||||
std::map<uint64_t, std::string> magics;
|
||||
if (onlyCheckAndroidMagics)
|
||||
magics.merge(PartitionMap::Extras::AndroidMagicMap);
|
||||
else if (onlyCheckFileSystemMagics)
|
||||
@@ -44,18 +50,16 @@ bool typeFunction::run() {
|
||||
else magics.merge(PartitionMap::Extras::MagicMap);
|
||||
|
||||
for (const auto &content : contents) {
|
||||
if (!Variables->PartMap->hasPartition(content) &&
|
||||
!Helper::fileIsExists(content))
|
||||
throw Error("Couldn't find partition or image file: %s\n",
|
||||
content.data());
|
||||
if (!PART_MAP.hasPartition(content) && !Helper::fileIsExists(content))
|
||||
throw Error("Couldn't find partition or image file: %s", content.data());
|
||||
|
||||
bool found = false;
|
||||
for (const auto &[magic, name] : magics) {
|
||||
if (PartitionMap::Extras::hasMagic(
|
||||
magic, bufferSize,
|
||||
magic, static_cast<ssize_t>(bufferSize),
|
||||
Helper::fileIsExists(content)
|
||||
? content
|
||||
: Variables->PartMap->getRealPathOf(content))) {
|
||||
: PART_MAP.getRealPathOf(content))) {
|
||||
println("%s contains %s magic (%s)", content.data(), name.data(),
|
||||
PartitionMap::Extras::formatMagic(magic).data());
|
||||
found = true;
|
||||
@@ -64,15 +68,15 @@ bool typeFunction::run() {
|
||||
}
|
||||
|
||||
if (!found)
|
||||
throw Error("Couldn't determine type of %s%s\n", content.data(),
|
||||
throw Error("Couldn't determine type of %s%s", content.data(),
|
||||
content == "userdata" ? " (encrypted file system?)" : "");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool typeFunction::isUsed() const { return cmd->parsed(); }
|
||||
IS_USED_COMMON_BODY
|
||||
|
||||
const char *typeFunction::name() const { return TFUN; }
|
||||
NAME { return TFUN; }
|
||||
|
||||
} // namespace PartitionManager
|
||||
|
||||
@@ -21,6 +21,25 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#define INIT bool FUNCTION_CLASS::init(CLI::App &_app)
|
||||
#define RUN bool FUNCTION_CLASS::run()
|
||||
#define RUN_ASYNC pair FUNCTION_CLASS::runAsync
|
||||
#define IS_USED bool FUNCTION_CLASS::isUsed() const
|
||||
#define IS_USED_COMMON_BODY \
|
||||
bool FUNCTION_CLASS::isUsed() const { return cmd->parsed(); }
|
||||
#define NAME const char *FUNCTION_CLASS::name() const
|
||||
|
||||
/**
|
||||
* Please define FUNCTION_CLASS before using these macros!!! (INIT etc.)
|
||||
*/
|
||||
|
||||
#define COMMON_FUNCTION_BODY() \
|
||||
CLI::App *cmd = nullptr; \
|
||||
bool init(CLI::App &_app) override; \
|
||||
bool run() override; \
|
||||
[[nodiscard]] bool isUsed() const override; \
|
||||
[[nodiscard]] const char *name() const override
|
||||
|
||||
namespace PartitionManager {
|
||||
using pair = std::pair<std::string, bool>;
|
||||
|
||||
@@ -29,18 +48,12 @@ class backupFunction final : public FunctionBase {
|
||||
private:
|
||||
std::vector<std::string> partitions, outputNames;
|
||||
std::string rawPartitions, rawOutputNames, outputDirectory;
|
||||
int bufferSize = 4096;
|
||||
uint64_t bufferSize = 0;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
static pair runAsync(const std::string &partitionName,
|
||||
const std::string &outputName, int bufferSize);
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
const std::string &outputName, uint64_t bufferSize);
|
||||
};
|
||||
|
||||
// Image flasher function
|
||||
@@ -48,35 +61,25 @@ class flashFunction final : public FunctionBase {
|
||||
private:
|
||||
std::vector<std::string> partitions, imageNames;
|
||||
std::string rawPartitions, rawImageNames, imageDirectory;
|
||||
int bufferSize = 4096;
|
||||
uint64_t bufferSize = 0;
|
||||
bool deleteAfterProgress = false;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
static pair runAsync(const std::string &partitionName,
|
||||
const std::string &imageName, int bufferSize);
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
const std::string &imageName, uint64_t bufferSize,
|
||||
bool deleteAfterProgress);
|
||||
};
|
||||
|
||||
// Eraser function (writes zero bytes to partition)
|
||||
class eraseFunction final : public FunctionBase {
|
||||
private:
|
||||
std::vector<std::string> partitions;
|
||||
int bufferSize = 4096;
|
||||
uint64_t bufferSize = 0;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
static pair runAsync(const std::string &partitionName, int bufferSize);
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
static pair runAsync(const std::string &partitionName, uint64_t bufferSize);
|
||||
};
|
||||
|
||||
// Partition size getter function
|
||||
@@ -87,75 +90,39 @@ private:
|
||||
asGiga = false;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
};
|
||||
|
||||
// Partition info getter function
|
||||
class infoFunction final : public FunctionBase {
|
||||
private:
|
||||
std::vector<std::string> partitions;
|
||||
std::string jNamePartition = "name", jNameSize = "size",
|
||||
jNameLogical = "isLogical";
|
||||
bool jsonFormat = false;
|
||||
std::string jNamePartition, jNameSize, jNameLogical;
|
||||
int jIndentSize = 2;
|
||||
bool jsonFormat = false, asByte = true, asKiloBytes = false, asMega = false,
|
||||
asGiga = false;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
};
|
||||
|
||||
class realPathFunction final : public FunctionBase {
|
||||
private:
|
||||
std::vector<std::string> partitions;
|
||||
bool realLinkPath = false;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
};
|
||||
|
||||
class realLinkPathFunction final : public FunctionBase {
|
||||
private:
|
||||
std::vector<std::string> partitions;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
};
|
||||
|
||||
class typeFunction final : public FunctionBase {
|
||||
private:
|
||||
std::vector<std::string> contents;
|
||||
bool onlyCheckAndroidMagics = false, onlyCheckFileSystemMagics = false;
|
||||
int bufferSize = 4096;
|
||||
uint64_t bufferSize = 0;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
};
|
||||
|
||||
class rebootFunction final : public FunctionBase {
|
||||
@@ -163,14 +130,24 @@ private:
|
||||
std::string rebootTarget;
|
||||
|
||||
public:
|
||||
CLI::App *cmd = nullptr;
|
||||
|
||||
bool init(CLI::App &_app) override;
|
||||
bool run() override;
|
||||
|
||||
[[nodiscard]] bool isUsed() const override;
|
||||
[[nodiscard]] const char *name() const override;
|
||||
COMMON_FUNCTION_BODY();
|
||||
};
|
||||
|
||||
class memoryTestFunction final : public FunctionBase {
|
||||
private:
|
||||
uint64_t bufferSize = MB(4), /* bufferSizeRandom = KB(4),*/ testFileSize = 0;
|
||||
std::string testPath;
|
||||
bool doNotReadTest = false;
|
||||
|
||||
public:
|
||||
COMMON_FUNCTION_BODY();
|
||||
};
|
||||
|
||||
class cleanLogFunction final : public FunctionBase {
|
||||
public:
|
||||
COMMON_FUNCTION_BODY();
|
||||
};
|
||||
|
||||
} // namespace PartitionManager
|
||||
|
||||
#endif // #ifndef FUNCTIONS_HPP
|
||||
|
||||
@@ -18,13 +18,25 @@
|
||||
#define LIBHELPER_LIB_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <dirent.h>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#define KB(x) (static_cast<uint64_t>(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 TO_KB(x) (x / 1024) // TO_KB(1024) = 1
|
||||
#define TO_MB(x) (TO_KB(x) / 1024) // TO_MB(2048) (2048 / 1024)
|
||||
#define TO_GB(x) (TO_MB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024)
|
||||
|
||||
#ifndef ONLY_HELPER_MACROS
|
||||
|
||||
enum LogLevels {
|
||||
@@ -34,6 +46,13 @@ enum LogLevels {
|
||||
ABORT = static_cast<int>('A')
|
||||
};
|
||||
|
||||
enum sizeCastTypes {
|
||||
B = static_cast<int>('B'),
|
||||
KB = static_cast<int>('K'),
|
||||
MB = static_cast<int>('M'),
|
||||
GB = static_cast<int>('G')
|
||||
};
|
||||
|
||||
constexpr mode_t DEFAULT_FILE_PERMS = 0644;
|
||||
constexpr mode_t DEFAULT_EXTENDED_FILE_PERMS = 0755;
|
||||
constexpr mode_t DEFAULT_DIR_PERMS = 0755;
|
||||
@@ -41,17 +60,29 @@ constexpr int YES = 1;
|
||||
constexpr int NO = 0;
|
||||
|
||||
namespace Helper {
|
||||
// Throwable error class
|
||||
class Error final : public std::exception {
|
||||
private:
|
||||
std::string _message;
|
||||
std::ostringstream _oss;
|
||||
|
||||
public:
|
||||
__attribute__((format(printf, 2, 3))) explicit Error(const char *format, ...);
|
||||
|
||||
[[nodiscard]] const char *what() const noexcept override;
|
||||
};
|
||||
|
||||
// Logging
|
||||
class Logger final {
|
||||
private:
|
||||
LogLevels _level;
|
||||
std::ostringstream _oss;
|
||||
const char *_funcname, *_logFile, *_program_name, *_file;
|
||||
const char *_function_name, *_logFile, *_program_name, *_file;
|
||||
int _line;
|
||||
|
||||
public:
|
||||
Logger(LogLevels level, const char *func, const char *file, const char *name,
|
||||
const char *sfile, int line);
|
||||
const char *source_file, int line);
|
||||
|
||||
~Logger();
|
||||
|
||||
@@ -63,34 +94,467 @@ public:
|
||||
Logger &operator<<(std::ostream &(*msg)(std::ostream &));
|
||||
};
|
||||
|
||||
// Throwable error class
|
||||
class Error final : public std::exception {
|
||||
private:
|
||||
std::string _message;
|
||||
|
||||
public:
|
||||
__attribute__((format(printf, 2, 3))) explicit Error(const char *format, ...);
|
||||
|
||||
[[nodiscard]] const char *what() const noexcept override;
|
||||
};
|
||||
|
||||
// Close file descriptors and delete allocated array memory
|
||||
class garbageCollector {
|
||||
private:
|
||||
std::vector<char *> _ptrs_c;
|
||||
std::vector<uint8_t *> _ptrs_u;
|
||||
std::vector<std::function<void()>> _cleaners;
|
||||
std::vector<FILE *> _fps;
|
||||
std::vector<DIR *> _dps;
|
||||
std::vector<int> _fds;
|
||||
std::vector<std::string> _files;
|
||||
|
||||
public:
|
||||
~garbageCollector();
|
||||
|
||||
void delAfterProgress(char *&_ptr);
|
||||
void delAfterProgress(uint8_t *&_ptr);
|
||||
void closeAfterProgress(FILE *&_fp);
|
||||
template <typename T> void delAfterProgress(T *_ptr) {
|
||||
_cleaners.push_back([_ptr] { delete[] _ptr; });
|
||||
}
|
||||
|
||||
void delFileAfterProgress(const std::string &_path);
|
||||
void closeAfterProgress(FILE *_fp);
|
||||
void closeAfterProgress(DIR *_dp);
|
||||
void closeAfterProgress(int _fd);
|
||||
};
|
||||
|
||||
template <int max = 100, int start = 0, int count = 10, int d = 0>
|
||||
class Random {
|
||||
static_assert(max > start, "max is larger than start");
|
||||
static_assert(count > 1, "count is larger than 1");
|
||||
static_assert(count <= max - start, "count is greater than max-start");
|
||||
|
||||
public:
|
||||
static std::set<int> get() {
|
||||
std::set<int> set;
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
if constexpr (d > 0) {
|
||||
std::uniform_int_distribution<> dist(0, (max - start - 1) / d);
|
||||
while (set.size() < count)
|
||||
set.insert(start + dist(gen) * d);
|
||||
} else {
|
||||
std::uniform_int_distribution<> dist(start, max - 1);
|
||||
while (set.size() < count)
|
||||
set.insert(dist(gen));
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
static int getNumber() {
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
int ret;
|
||||
|
||||
if constexpr (d > 0) {
|
||||
std::uniform_int_distribution<> dist(0, (max - start - 1) / d);
|
||||
ret = start + dist(gen) * d;
|
||||
} else {
|
||||
std::uniform_int_distribution<> dist(start, max - 1); // max exclusive
|
||||
ret = dist(gen);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Type1, typename _Type2, typename _Type3> class PureTuple {
|
||||
private:
|
||||
void expand_if_needed() {
|
||||
if (count == capacity) {
|
||||
capacity *= 2;
|
||||
Data *data = new Data[capacity];
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
data[i] = tuple_data[i];
|
||||
|
||||
delete[] tuple_data;
|
||||
tuple_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
struct Data {
|
||||
_Type1 first;
|
||||
_Type2 second;
|
||||
_Type3 third;
|
||||
|
||||
bool
|
||||
operator==(const std::tuple<_Type1, _Type2, _Type3> &t) const noexcept {
|
||||
return first == std::get<0>(t) && second == std::get<1>(t) &&
|
||||
third == std::get<2>(t);
|
||||
}
|
||||
|
||||
bool operator==(const Data &other) const noexcept {
|
||||
return first == other.first && second == other.second &&
|
||||
third == other.third;
|
||||
}
|
||||
|
||||
bool operator!=(const Data &other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return first != _Type1{} || second != _Type2{} || third != _Type3{};
|
||||
}
|
||||
|
||||
bool operator!() const noexcept { return !bool{*this}; }
|
||||
|
||||
void operator()(const std::tuple<_Type1, _Type2, _Type3> &t) {
|
||||
first = std::get<0>(t);
|
||||
second = std::get<1>(t);
|
||||
third = std::get<2>(t);
|
||||
}
|
||||
|
||||
Data &operator=(const std::tuple<_Type1, _Type2, _Type3> &t) {
|
||||
first = std::get<0>(t);
|
||||
second = std::get<1>(t);
|
||||
third = std::get<2>(t);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
Data *tuple_data = nullptr;
|
||||
Data tuple_data_type = {_Type1{}, _Type2{}, _Type3{}};
|
||||
size_t capacity{}, count{};
|
||||
|
||||
PureTuple() : tuple_data(new Data[20]), capacity(20), count(0) {}
|
||||
~PureTuple() { delete[] tuple_data; }
|
||||
|
||||
PureTuple(std::initializer_list<Data> val)
|
||||
: tuple_data(new Data[20]), capacity(20), count(0) {
|
||||
for (const auto &v : val)
|
||||
insert(v);
|
||||
}
|
||||
PureTuple(PureTuple &other)
|
||||
: tuple_data(new Data[other.capacity]), capacity(other.capacity),
|
||||
count(other.count) {
|
||||
std::copy(other.tuple_data, other.tuple_data + count, tuple_data);
|
||||
}
|
||||
PureTuple(PureTuple &&other) noexcept
|
||||
: tuple_data(new Data[other.capacity]), capacity(other.capacity),
|
||||
count(other.count) {
|
||||
std::copy(other.tuple_data, other.tuple_data + count, tuple_data);
|
||||
other.clear();
|
||||
}
|
||||
|
||||
class iterator {
|
||||
private:
|
||||
Data *it;
|
||||
|
||||
public:
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = Data;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = Data *;
|
||||
using reference = Data &;
|
||||
|
||||
explicit iterator(Data *ptr) : it(ptr) {}
|
||||
|
||||
pointer operator->() const { return it; }
|
||||
reference operator*() { return *it; }
|
||||
|
||||
iterator &operator++() {
|
||||
++it;
|
||||
return *this;
|
||||
}
|
||||
iterator operator++(int) {
|
||||
iterator tmp = *this;
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
iterator &operator--() {
|
||||
--it;
|
||||
return *this;
|
||||
}
|
||||
iterator operator--(int) {
|
||||
iterator tmp = *this;
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
iterator &operator+=(difference_type n) {
|
||||
it += n;
|
||||
return *this;
|
||||
}
|
||||
iterator operator+(difference_type n) const { return iterator(it + n); }
|
||||
iterator &operator-=(difference_type n) {
|
||||
it -= n;
|
||||
return *this;
|
||||
}
|
||||
iterator operator-(difference_type n) const { return iterator(it - n); }
|
||||
difference_type operator-(const iterator &other) const {
|
||||
return it - other.it;
|
||||
}
|
||||
|
||||
reference operator[](difference_type n) const { return it[n]; }
|
||||
|
||||
bool operator<(const iterator &other) const { return it < other.it; }
|
||||
bool operator>(const iterator &other) const { return it > other.it; }
|
||||
bool operator<=(const iterator &other) const { return it <= other.it; }
|
||||
bool operator>=(const iterator &other) const { return it >= other.it; }
|
||||
|
||||
bool operator!=(const iterator &other) const { return it != other.it; }
|
||||
bool operator==(const iterator &other) const { return it == other.it; }
|
||||
};
|
||||
|
||||
bool find(const Data &data) const noexcept {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
if (data == tuple_data[i]) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T = std::tuple<_Type1, _Type2, _Type3>>
|
||||
std::enable_if_t<std::is_same_v<T, std::tuple<_Type1, _Type2, _Type3>>, bool>
|
||||
find(const std::tuple<_Type1, _Type2, _Type3> &t) const noexcept {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
if (tuple_data[i] == t) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool find(const _Type1 &val, const _Type2 &val2,
|
||||
const _Type3 &val3) const noexcept {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
if (tuple_data[i] == std::make_tuple(val, val2, val3)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void insert(const Data &val) noexcept {
|
||||
expand_if_needed();
|
||||
if (!find(val)) tuple_data[count++] = val;
|
||||
}
|
||||
|
||||
template <typename T = std::tuple<_Type1, _Type2, _Type3>>
|
||||
std::enable_if_t<std::is_same_v<T, std::tuple<_Type1, _Type2, _Type3>>, void>
|
||||
insert(const std::tuple<_Type1, _Type2, _Type3> &t) noexcept {
|
||||
expand_if_needed();
|
||||
if (!find(t))
|
||||
tuple_data[count++] =
|
||||
Data{std::get<0>(t), std::get<1>(t), std::get<2>(t)};
|
||||
}
|
||||
|
||||
void insert(const _Type1 &val, const _Type2 &val2,
|
||||
const _Type3 &val3) noexcept {
|
||||
expand_if_needed();
|
||||
if (!find(val, val2, val3)) tuple_data[count++] = Data{val, val2, val3};
|
||||
}
|
||||
|
||||
void merge(const PureTuple &other) noexcept {
|
||||
for (const auto &v : other)
|
||||
insert(v);
|
||||
}
|
||||
|
||||
void pop_back() noexcept {
|
||||
if (count > 0) --count;
|
||||
}
|
||||
|
||||
void pop(const Data &data) noexcept {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (tuple_data[i] == data) {
|
||||
for (size_t j = i; j < count - 1; j++)
|
||||
tuple_data[j] = tuple_data[j + 1];
|
||||
--count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop(const size_t i) noexcept {
|
||||
if (i >= count) return;
|
||||
for (size_t x = 0; x < count; x++) {
|
||||
if (i == x) {
|
||||
for (size_t j = i; j < count - 1; j++)
|
||||
tuple_data[j] = tuple_data[j + 1];
|
||||
--count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop(const _Type1 &val, const _Type2 &val2, const _Type3 &val3) noexcept {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (tuple_data[i] == std::make_tuple(val, val2, val3)) {
|
||||
for (size_t j = i; j < count - 1; j++)
|
||||
tuple_data[j] = tuple_data[j + 1];
|
||||
--count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T = std::tuple<_Type1, _Type2, _Type3>>
|
||||
std::enable_if_t<std::is_same_v<T, std::tuple<_Type1, _Type2, _Type3>>, void>
|
||||
pop(const std::tuple<_Type1, _Type2, _Type3> &t) noexcept {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (tuple_data[i] == t) {
|
||||
for (size_t j = i; j < count - 1; j++)
|
||||
tuple_data[j] = tuple_data[j + 1];
|
||||
--count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear() noexcept {
|
||||
delete[] tuple_data;
|
||||
count = 0;
|
||||
capacity = 20;
|
||||
tuple_data = new Data[capacity];
|
||||
}
|
||||
|
||||
Data back() const noexcept {
|
||||
return (count > 0) ? tuple_data[count - 1] : Data{};
|
||||
}
|
||||
Data top() const noexcept { return (count > 0) ? tuple_data[0] : Data{}; }
|
||||
|
||||
Data at(size_t i) const noexcept {
|
||||
if (i >= count) return Data{};
|
||||
return tuple_data[i];
|
||||
}
|
||||
|
||||
void foreach (std::function<void(_Type1, _Type2, _Type3)> func) {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
func(tuple_data[i].first, tuple_data[i].second, tuple_data[i].third);
|
||||
}
|
||||
|
||||
void foreach (std::function<void(std::tuple<_Type1, _Type2, _Type3>)> func) {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
func(std::make_tuple(tuple_data[i].first, tuple_data[i].second,
|
||||
tuple_data[i].third));
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t size() const noexcept { return count; }
|
||||
[[nodiscard]] bool empty() const noexcept { return count == 0; }
|
||||
|
||||
iterator begin() const noexcept { return iterator(tuple_data); }
|
||||
iterator end() const noexcept { return iterator(tuple_data + count); }
|
||||
|
||||
explicit operator bool() const noexcept { return count > 0; }
|
||||
bool operator!() const noexcept { return count == 0; }
|
||||
|
||||
bool operator==(const PureTuple &other) const noexcept {
|
||||
if (this->count != other.count || this->capacity != other.capacity)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < this->count; i++)
|
||||
if (tuple_data[i] != other.tuple_data[i]) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const PureTuple &other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
Data operator[](size_t i) const noexcept {
|
||||
if (i >= count) return Data{};
|
||||
return tuple_data[i];
|
||||
}
|
||||
explicit operator int() const noexcept { return count; }
|
||||
|
||||
PureTuple &operator=(const PureTuple &other) {
|
||||
if (this != &other) {
|
||||
delete[] tuple_data;
|
||||
|
||||
capacity = other.capacity;
|
||||
count = other.count;
|
||||
tuple_data = new Data[capacity];
|
||||
|
||||
std::copy(other.tuple_data, other.tuple_data + count, tuple_data);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PureTuple &operator<<(const std::tuple<_Type1, _Type2, _Type3> &t) noexcept {
|
||||
insert(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend PureTuple &operator>>(const std::tuple<_Type1, _Type2, _Type3> &t,
|
||||
PureTuple &tuple) noexcept {
|
||||
tuple.insert(t);
|
||||
return tuple;
|
||||
}
|
||||
};
|
||||
|
||||
// Provides a capsule structure to store variable references and values.
|
||||
template <typename _Type> class Capsule : public garbageCollector {
|
||||
public:
|
||||
_Type &value;
|
||||
|
||||
// The value to be stored is taken as a reference as an argument
|
||||
explicit Capsule(_Type &value) noexcept : value(value) {}
|
||||
|
||||
// Set the value.
|
||||
void set(const _Type &_value) noexcept { this->value = _value; }
|
||||
void set(_Type &_value) noexcept { this->value = _value; }
|
||||
|
||||
// Get reference of the value.
|
||||
_Type &get() noexcept { return this->value; }
|
||||
const _Type &get() const noexcept { return this->value; }
|
||||
|
||||
// You can get the reference of the stored value in the input type (casting is
|
||||
// required).
|
||||
operator _Type &() noexcept { return this->value; }
|
||||
operator const _Type &() const noexcept { return this->value; }
|
||||
explicit operator _Type *() noexcept { return &this->value; }
|
||||
|
||||
// The value of another capsule is taken.
|
||||
Capsule &operator=(const Capsule &other) noexcept {
|
||||
this->value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assign another value.
|
||||
Capsule &operator=(const _Type &_value) noexcept {
|
||||
this->value = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Check if this capsule and another capsule hold the same data.
|
||||
bool operator==(const Capsule &other) const noexcept {
|
||||
return this->value == other.value;
|
||||
}
|
||||
|
||||
// Check if this capsule value and another capsule value hold the same data.
|
||||
bool operator==(const _Type &_value) const noexcept {
|
||||
return this->value == _value;
|
||||
}
|
||||
|
||||
// Check that this capsule and another capsule do not hold the same data.
|
||||
bool operator!=(const Capsule &other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// Check that this capsule value and another capsule value do not hold the
|
||||
// same data.
|
||||
bool operator!=(const _Type &_value) const noexcept {
|
||||
return !(*this == _value);
|
||||
}
|
||||
|
||||
// Check if the current held value is actually empty.
|
||||
explicit operator bool() const noexcept { return this->value != _Type{}; }
|
||||
|
||||
// Check that the current held value is actually empty.
|
||||
bool operator!() const noexcept { return this->value == _Type{}; }
|
||||
|
||||
// Change the value with the input operator.
|
||||
friend Capsule &operator>>(const _Type &_value, Capsule &_capsule) noexcept {
|
||||
_capsule.value = _value;
|
||||
return _capsule;
|
||||
}
|
||||
|
||||
// Get the reference of the value held.
|
||||
_Type &operator()() noexcept { return value; }
|
||||
const _Type &operator()() const noexcept { return value; }
|
||||
|
||||
// Set the value.
|
||||
void operator()(const _Type &_value) noexcept { this->value = _value; }
|
||||
};
|
||||
|
||||
namespace LoggingProperties {
|
||||
extern std::string_view FILE, NAME;
|
||||
extern bool PRINT, DISABLE;
|
||||
@@ -98,89 +562,307 @@ extern bool PRINT, DISABLE;
|
||||
void set(std::string_view name, std::string_view file);
|
||||
void setProgramName(std::string_view name);
|
||||
void setLogFile(std::string_view file);
|
||||
void setPrinting(int state);
|
||||
void setLoggingState(int state); // Disable/enable logging
|
||||
|
||||
template <int state> void setPrinting() {
|
||||
if (state == 1 || state == 0) PRINT = state;
|
||||
else PRINT = NO;
|
||||
}
|
||||
template <int state> void setLoggingState() {
|
||||
if (state == 1 || state == 0) DISABLE = state;
|
||||
else DISABLE = NO;
|
||||
}
|
||||
|
||||
void reset();
|
||||
} // namespace LoggingProperties
|
||||
|
||||
// Checkers
|
||||
// -------------------------------
|
||||
// Checkers - not throws Helper::Error
|
||||
// -------------------------------
|
||||
|
||||
/**
|
||||
* It is checked whether the user ID used is equivalent to AID_ROOT.
|
||||
* See include/private/android_filesystem_config.h
|
||||
*/
|
||||
bool hasSuperUser();
|
||||
|
||||
/**
|
||||
* It is checked whether the user ID used is equivalent to AID_SHELL.
|
||||
* See include/private/android_filesystem_config.h
|
||||
*/
|
||||
bool hasAdbPermissions();
|
||||
|
||||
/**
|
||||
* Checks whether the file/directory exists.
|
||||
*/
|
||||
bool isExists(std::string_view entry);
|
||||
|
||||
/**
|
||||
* Checks whether the file exists.
|
||||
*/
|
||||
bool fileIsExists(std::string_view file);
|
||||
|
||||
/**
|
||||
* Checks whether the directory exists.
|
||||
*/
|
||||
bool directoryIsExists(std::string_view directory);
|
||||
|
||||
/**
|
||||
* Checks whether the link (symbolic or hard) exists.
|
||||
*/
|
||||
bool linkIsExists(std::string_view entry);
|
||||
|
||||
/**
|
||||
* Checks if the entry is a symbolic link.
|
||||
*/
|
||||
bool isLink(std::string_view entry);
|
||||
|
||||
/**
|
||||
* Checks if the entry is a symbolic link.
|
||||
*/
|
||||
bool isSymbolicLink(std::string_view entry);
|
||||
|
||||
/**
|
||||
* Checks if the entry is a hard link.
|
||||
*/
|
||||
bool isHardLink(std::string_view entry);
|
||||
|
||||
/**
|
||||
* Checks whether entry1 is linked to entry2.
|
||||
*/
|
||||
bool areLinked(std::string_view entry1, std::string_view entry2);
|
||||
|
||||
// File I/O
|
||||
// -------------------------------
|
||||
// File I/O - not throws Helper::Error
|
||||
// -------------------------------
|
||||
|
||||
/**
|
||||
* Writes given text into file.
|
||||
* If file does not exist, it is automatically created.
|
||||
* Returns true on success.
|
||||
*/
|
||||
bool writeFile(std::string_view file, std::string_view text);
|
||||
|
||||
/**
|
||||
* Reads file content into string.
|
||||
* On success returns file content.
|
||||
* On error returns std::nullopt.
|
||||
*/
|
||||
std::optional<std::string> readFile(std::string_view file);
|
||||
|
||||
// -------------------------------
|
||||
// Creators
|
||||
// -------------------------------
|
||||
|
||||
/**
|
||||
* Create directory.
|
||||
*/
|
||||
bool makeDirectory(std::string_view path);
|
||||
|
||||
/**
|
||||
* Create recursive directory.
|
||||
*/
|
||||
bool makeRecursiveDirectory(std::string_view paths);
|
||||
|
||||
/**
|
||||
* Create file.
|
||||
*/
|
||||
bool createFile(std::string_view path);
|
||||
|
||||
/**
|
||||
* Symlink entry1 to entry2.
|
||||
*/
|
||||
bool createSymlink(std::string_view entry1, std::string_view entry2);
|
||||
|
||||
// Removers
|
||||
// -------------------------------
|
||||
// Removers - not throws Helper::Error
|
||||
// -------------------------------
|
||||
|
||||
/**
|
||||
* Remove file or empty directory.
|
||||
*/
|
||||
bool eraseEntry(std::string_view entry);
|
||||
|
||||
/**
|
||||
* Remove directory and all directory contents recursively.
|
||||
*/
|
||||
bool eraseDirectoryRecursive(std::string_view directory);
|
||||
|
||||
// Getters
|
||||
size_t fileSize(std::string_view file);
|
||||
// -------------------------------
|
||||
// Getters - not throws Helper::Error
|
||||
// -------------------------------
|
||||
|
||||
/**
|
||||
* Get file size.
|
||||
*/
|
||||
int64_t fileSize(std::string_view file);
|
||||
|
||||
/**
|
||||
* Read symlinks.
|
||||
*/
|
||||
std::string readSymlink(std::string_view entry);
|
||||
|
||||
// -------------------------------
|
||||
// SHA-256
|
||||
// -------------------------------
|
||||
|
||||
/**
|
||||
* Compare SHA-256 values SHA-256 of files.
|
||||
* Throws Helper::Error on error occurred.
|
||||
*/
|
||||
bool sha256Compare(std::string_view file1, std::string_view file2);
|
||||
|
||||
/**
|
||||
* Get SHA-256 of file.
|
||||
* Throws Helper::Error on error occurred.
|
||||
*/
|
||||
std::optional<std::string> sha256Of(std::string_view path);
|
||||
|
||||
// Utilities
|
||||
// -------------------------------
|
||||
// Utilities - not throws Helper::Error
|
||||
// -------------------------------
|
||||
|
||||
/**
|
||||
* Copy file to dest.
|
||||
*/
|
||||
bool copyFile(std::string_view file, std::string_view dest);
|
||||
|
||||
/**
|
||||
* Run shell command.
|
||||
*/
|
||||
bool runCommand(std::string_view cmd);
|
||||
|
||||
/**
|
||||
* Shows message and asks for y/N from user.
|
||||
*/
|
||||
bool confirmPropt(std::string_view message);
|
||||
|
||||
/**
|
||||
* Change file permissions.
|
||||
*/
|
||||
bool changeMode(std::string_view file, mode_t mode);
|
||||
|
||||
/**
|
||||
* Change file owner (user ID and group ID).
|
||||
*/
|
||||
bool changeOwner(std::string_view file, uid_t uid, gid_t gid);
|
||||
|
||||
/**
|
||||
* Get current working directory as string.
|
||||
* Returns empty string on error.
|
||||
*/
|
||||
std::string currentWorkingDirectory();
|
||||
|
||||
/**
|
||||
* Get current date as string (format: YYYY-MM-DD).
|
||||
* Returns empty string on error.
|
||||
*/
|
||||
std::string currentDate();
|
||||
|
||||
/**
|
||||
* Get current time as string (format: HH:MM:SS).
|
||||
* Returns empty string on error.
|
||||
*/
|
||||
std::string currentTime();
|
||||
std::string runCommandWithOutput(std::string_view cmd);
|
||||
|
||||
/**
|
||||
* Run shell command return output as string.
|
||||
* Returns std::pair<std::string, int>.
|
||||
*/
|
||||
std::pair<std::string, int> runCommandWithOutput(std::string_view cmd);
|
||||
|
||||
/**
|
||||
* Joins base path with relative path and returns result.
|
||||
*/
|
||||
std::string pathJoin(std::string base, std::string relative);
|
||||
|
||||
/**
|
||||
* Get the filename part of given path.
|
||||
*/
|
||||
std::string pathBasename(std::string_view entry);
|
||||
|
||||
/**
|
||||
* Get the directory part of given path.
|
||||
*/
|
||||
std::string pathDirname(std::string_view entry);
|
||||
|
||||
// Android
|
||||
std::string getProperty(std::string_view prop);
|
||||
bool reboot(std::string_view arg);
|
||||
/**
|
||||
* Get random offset depending on size and bufferSize.
|
||||
*/
|
||||
uint64_t getRandomOffset(uint64_t size, uint64_t bufferSize);
|
||||
|
||||
// Library-specif
|
||||
/**
|
||||
* Convert input size to input multiple.
|
||||
*/
|
||||
int convertTo(uint64_t size, sizeCastTypes type);
|
||||
|
||||
/**
|
||||
* Convert input multiple variable to string.
|
||||
*/
|
||||
std::string multipleToString(sizeCastTypes type);
|
||||
|
||||
/**
|
||||
* Format it input and return as std::string.
|
||||
*/
|
||||
__attribute__((format(printf, 1, 2))) std::string format(const char *format,
|
||||
...);
|
||||
|
||||
/**
|
||||
* Convert input size to input multiple
|
||||
*/
|
||||
template <uint64_t size> int convertTo(const sizeCastTypes type) {
|
||||
if (type == KB) return TO_KB(size);
|
||||
if (type == MB) return TO_MB(size);
|
||||
if (type == GB) return TO_GB(size);
|
||||
return static_cast<int>(size);
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Android - not throws Helper::Error
|
||||
// -------------------------------
|
||||
#ifdef __ANDROID__
|
||||
/**
|
||||
* Get input property as string (for Android).
|
||||
*/
|
||||
std::string getProperty(std::string_view prop);
|
||||
|
||||
/**
|
||||
* Reboot device to input mode (for Android).
|
||||
*/
|
||||
bool androidReboot(std::string_view arg);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get libhelper library version string.
|
||||
*/
|
||||
std::string getLibVersion();
|
||||
|
||||
// Open input path with flags and add to integrity list. And return file
|
||||
// descriptor
|
||||
/**
|
||||
* Open input path with flags and add to integrity list.
|
||||
* And returns file descriptor.
|
||||
*/
|
||||
[[nodiscard]] int openAndAddToCloseList(const std::string_view &path,
|
||||
garbageCollector &collector, int flags,
|
||||
mode_t mode = 0000);
|
||||
/**
|
||||
* Open input path with flags and add to integrity list.
|
||||
* And returns file pointer.
|
||||
*/
|
||||
[[nodiscard]] FILE *openAndAddToCloseList(const std::string_view &path,
|
||||
garbageCollector &collector,
|
||||
const char *mode);
|
||||
/**
|
||||
* Open input directory and add to integrity list.
|
||||
* And returns directory pointer.
|
||||
*/
|
||||
[[nodiscard]] DIR *openAndAddToCloseList(const std::string_view &path,
|
||||
garbageCollector &collector);
|
||||
|
||||
} // namespace Helper
|
||||
|
||||
#endif // #ifndef ONLY_HELPER_MACROS
|
||||
|
||||
#define HELPER "libhelper"
|
||||
|
||||
#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 TO_KB(x) (x / 1024) // TO_KB(1024) = 1
|
||||
#define TO_MB(x) (TO_KB(x) / 1024) // TO_MB(2048) (2048 / 1024)
|
||||
#define TO_GB(x) (TO_MB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024)
|
||||
|
||||
#define STYLE_RESET "\033[0m"
|
||||
#define BOLD "\033[1m"
|
||||
#define FAINT "\033[2m"
|
||||
@@ -223,6 +905,9 @@ std::string getLibVersion();
|
||||
#define LOG(level) \
|
||||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||||
#define LOGF(file, level) \
|
||||
Helper::Logger(level, __func__, file, \
|
||||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||||
#define LOGN(name, level) \
|
||||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||||
name, __FILE__, __LINE__)
|
||||
@@ -233,6 +918,10 @@ std::string getLibVersion();
|
||||
if (condition) \
|
||||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||||
#define LOGF_IF(file, level, condition) \
|
||||
if (condition) \
|
||||
Helper::Logger(level, __func__, file, \
|
||||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||||
#define LOGN_IF(name, level, condition) \
|
||||
if (condition) \
|
||||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||||
@@ -240,6 +929,15 @@ std::string getLibVersion();
|
||||
#define LOGNF_IF(name, file, level, condition) \
|
||||
if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__)
|
||||
|
||||
#ifdef ANDROID_BUILD
|
||||
#define MKVERSION(name) \
|
||||
char vinfo[512]; \
|
||||
sprintf(vinfo, \
|
||||
"%s 1.3.0\nCompiler: clang\n" \
|
||||
"BuildFlags: -Wall;-Werror;-Wno-deprecated-declarations;-Os", \
|
||||
name); \
|
||||
return std::string(vinfo)
|
||||
#else
|
||||
#define MKVERSION(name) \
|
||||
char vinfo[512]; \
|
||||
sprintf(vinfo, \
|
||||
@@ -248,5 +946,6 @@ std::string getLibVersion();
|
||||
name, BUILD_VERSION, BUILD_DATE, BUILD_TIME, BUILD_TYPE, \
|
||||
BUILD_CMAKE_VERSION, BUILD_COMPILER_VERSION, BUILD_FLAGS); \
|
||||
return std::string(vinfo)
|
||||
#endif
|
||||
|
||||
#endif // #ifndef LIBHELPER_LIB_HPP
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dirent.h>
|
||||
#include <exception>
|
||||
#include <fcntl.h>
|
||||
#include <functional>
|
||||
#include <libgen.h>
|
||||
#include <libhelper/lib.hpp>
|
||||
#include <sstream>
|
||||
@@ -40,9 +42,9 @@ Error::Error(const char *format, ...) {
|
||||
const char *Error::what() const noexcept { return _message.data(); }
|
||||
|
||||
Logger::Logger(const LogLevels level, const char *func, const char *file,
|
||||
const char *name, const char *sfile, const int line)
|
||||
: _level(level), _funcname(func), _logFile(file), _program_name(name),
|
||||
_file(sfile), _line(line) {}
|
||||
const char *name, const char *source_file, const int line)
|
||||
: _level(level), _function_name(func), _logFile(file), _program_name(name),
|
||||
_file(source_file), _line(line) {}
|
||||
|
||||
Logger::~Logger() {
|
||||
if (LoggingProperties::DISABLE) return;
|
||||
@@ -50,7 +52,7 @@ Logger::~Logger() {
|
||||
snprintf(str, sizeof(str), "<%c> [ <prog %s> <on %s:%d> %s %s] %s(): %s",
|
||||
static_cast<char>(_level), _program_name,
|
||||
basename(const_cast<char *>(_file)), _line, currentDate().data(),
|
||||
currentTime().data(), _funcname, _oss.str().data());
|
||||
currentTime().data(), _function_name, _oss.str().data());
|
||||
|
||||
if (!isExists(_logFile)) {
|
||||
if (const int fd =
|
||||
@@ -58,11 +60,19 @@ Logger::~Logger() {
|
||||
fd != -1)
|
||||
close(fd);
|
||||
else {
|
||||
#ifdef ANDROID_BUILD
|
||||
LoggingProperties::setLogFile("/tmp/last_pmt_logs.log")
|
||||
#else
|
||||
LoggingProperties::setLogFile("last_logs.log");
|
||||
LOGN(HELPER, INFO) << "Cannot create log file: " << _logFile << ": "
|
||||
<< strerror(errno)
|
||||
<< " New logging file: last_logs.log (this file)."
|
||||
<< std::endl;
|
||||
#endif
|
||||
LOGN(HELPER, INFO)
|
||||
<< "Cannot create log file: " << _logFile << ": " << strerror(errno)
|
||||
#ifdef ANDROID_BUILD
|
||||
<< " New logging file: /tmp/last_pmt_logs.log (this file)."
|
||||
#else
|
||||
<< " New logging file: last_logs.log (this file)."
|
||||
#endif
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,24 +97,24 @@ Logger &Logger::operator<<(std::ostream &(*msg)(std::ostream &)) {
|
||||
}
|
||||
|
||||
garbageCollector::~garbageCollector() {
|
||||
for (const auto &ptr : _ptrs_c)
|
||||
delete[] ptr;
|
||||
for (const auto &ptr : _ptrs_u)
|
||||
delete[] ptr;
|
||||
for (auto &ptr_func : _cleaners)
|
||||
ptr_func();
|
||||
for (const auto &fd : _fds)
|
||||
close(fd);
|
||||
for (const auto &fp : _fps)
|
||||
fclose(fp);
|
||||
for (const auto &dp : _dps)
|
||||
closedir(dp);
|
||||
for (const auto &file : _files)
|
||||
eraseEntry(file);
|
||||
}
|
||||
|
||||
void garbageCollector::delAfterProgress(char *&_ptr) {
|
||||
_ptrs_c.push_back(_ptr);
|
||||
}
|
||||
void garbageCollector::delAfterProgress(uint8_t *&_ptr) {
|
||||
_ptrs_u.push_back(_ptr);
|
||||
void garbageCollector::delFileAfterProgress(const std::string &_path) {
|
||||
_files.push_back(_path);
|
||||
}
|
||||
void garbageCollector::closeAfterProgress(const int _fd) {
|
||||
_fds.push_back(_fd);
|
||||
}
|
||||
void garbageCollector::closeAfterProgress(FILE *&_fp) { _fps.push_back(_fp); }
|
||||
void garbageCollector::closeAfterProgress(FILE *_fp) { _fps.push_back(_fp); }
|
||||
void garbageCollector::closeAfterProgress(DIR *_dp) { _dps.push_back(_dp); }
|
||||
} // namespace Helper
|
||||
|
||||
@@ -151,8 +151,9 @@ bool eraseDirectoryRecursive(const std::string_view directory) {
|
||||
LOGN(HELPER, INFO) << "erase recursive requested: " << directory << std::endl;
|
||||
struct stat buf{};
|
||||
dirent *entry;
|
||||
garbageCollector collector;
|
||||
|
||||
DIR *dir = opendir(directory.data());
|
||||
DIR *dir = openAndAddToCloseList(directory.data(), collector);
|
||||
if (dir == nullptr) return false;
|
||||
|
||||
while ((entry = readdir(dir)) != nullptr) {
|
||||
@@ -164,25 +165,17 @@ bool eraseDirectoryRecursive(const std::string_view directory) {
|
||||
snprintf(fullpath, sizeof(fullpath), "%s/%s", directory.data(),
|
||||
entry->d_name);
|
||||
|
||||
if (lstat(fullpath, &buf) == -1) {
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
if (lstat(fullpath, &buf) == -1) return false;
|
||||
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
if (!eraseDirectoryRecursive(fullpath)) {
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
if (!eraseDirectoryRecursive(fullpath)) return false;
|
||||
} else if (S_ISREG(buf.st_mode)) {
|
||||
if (!eraseEntry(fullpath)) return false;
|
||||
} else {
|
||||
if (unlink(fullpath) == -1) {
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
if (unlink(fullpath) == -1) return false;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
if (rmdir(directory.data()) == -1) return false;
|
||||
|
||||
LOGN(HELPER, INFO) << "\"" << directory << "\" successfully erased."
|
||||
@@ -203,10 +196,10 @@ std::string readSymlink(const std::string_view entry) {
|
||||
return target;
|
||||
}
|
||||
|
||||
size_t fileSize(const std::string_view file) {
|
||||
int64_t fileSize(const std::string_view file) {
|
||||
LOGN(HELPER, INFO) << "get file size request: " << file << std::endl;
|
||||
struct stat st{};
|
||||
if (stat(file.data(), &st) != 0) return false;
|
||||
return static_cast<size_t>(st.st_size);
|
||||
if (stat(file.data(), &st) != 0) return -1;
|
||||
return st.st_size;
|
||||
}
|
||||
} // namespace Helper
|
||||
|
||||
@@ -19,7 +19,14 @@
|
||||
#include <ctime>
|
||||
#include <cutils/android_reboot.h>
|
||||
#include <fcntl.h>
|
||||
#ifndef ANDROID_BUILD
|
||||
#include <generated/buildInfo.hpp>
|
||||
#include <sys/_system_properties.h>
|
||||
#else
|
||||
#include <sys/system_properties.h>
|
||||
#endif
|
||||
#include <cstdarg>
|
||||
#include <cutils/android_reboot.h>
|
||||
#include <iostream>
|
||||
#include <libgen.h>
|
||||
#include <libhelper/lib.hpp>
|
||||
@@ -30,6 +37,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// From system/core/libcutils/android_reboot.cpp android16-s2-release
|
||||
int android_reboot(const unsigned cmd, int /*flags*/, const char *arg) {
|
||||
int ret;
|
||||
@@ -58,6 +66,7 @@ int android_reboot(const unsigned cmd, int /*flags*/, const char *arg) {
|
||||
free(prop_value);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Helper {
|
||||
namespace LoggingProperties {
|
||||
@@ -77,16 +86,6 @@ void set(std::string_view file, std::string_view name) {
|
||||
|
||||
void setProgramName(const std::string_view name) { NAME = name; }
|
||||
void setLogFile(const std::string_view file) { FILE = file; }
|
||||
|
||||
void setPrinting(const int state) {
|
||||
if (state == 1 || state == 0) PRINT = state;
|
||||
else PRINT = NO;
|
||||
}
|
||||
|
||||
void setLoggingState(const int state) {
|
||||
if (state == 1 || state == 0) DISABLE = state;
|
||||
else DISABLE = NO;
|
||||
}
|
||||
} // namespace LoggingProperties
|
||||
|
||||
bool runCommand(const std::string_view cmd) {
|
||||
@@ -121,7 +120,7 @@ std::string currentDate() {
|
||||
return std::string(std::to_string(date->tm_mday) + "/" +
|
||||
std::to_string(date->tm_mon + 1) + "/" +
|
||||
std::to_string(date->tm_year + 1900));
|
||||
return "--/--/----";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string currentTime() {
|
||||
@@ -131,10 +130,10 @@ std::string currentTime() {
|
||||
return std::string(std::to_string(date->tm_hour) + ":" +
|
||||
std::to_string(date->tm_min) + ":" +
|
||||
std::to_string(date->tm_sec));
|
||||
return "--:--:--";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string runCommandWithOutput(const std::string_view cmd) {
|
||||
std::pair<std::string, int> runCommandWithOutput(const std::string_view cmd) {
|
||||
LOGN(HELPER, INFO) << "run command and catch out request: " << cmd
|
||||
<< std::endl;
|
||||
|
||||
@@ -149,7 +148,9 @@ std::string runCommandWithOutput(const std::string_view cmd) {
|
||||
while (fgets(buffer, sizeof(buffer), pipe_holder.get()) != nullptr)
|
||||
output += buffer;
|
||||
|
||||
return output;
|
||||
FILE *raw = pipe_holder.release();
|
||||
const int status = pclose(raw);
|
||||
return {output, (WIFEXITED(status) ? WEXITSTATUS(status) : -1)};
|
||||
}
|
||||
|
||||
std::string pathJoin(std::string base, std::string relative) {
|
||||
@@ -198,13 +199,21 @@ FILE *openAndAddToCloseList(const std::string_view &path,
|
||||
return fp;
|
||||
}
|
||||
|
||||
DIR *openAndAddToCloseList(const std::string_view &path,
|
||||
garbageCollector &collector) {
|
||||
DIR *dp = opendir(path.data());
|
||||
collector.closeAfterProgress(dp);
|
||||
return dp;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
std::string getProperty(const std::string_view prop) {
|
||||
char val[PROP_VALUE_MAX];
|
||||
const int x = __system_property_get(prop.data(), val);
|
||||
return x > 0 ? val : "ERROR";
|
||||
}
|
||||
|
||||
bool reboot(const std::string_view arg) {
|
||||
bool androidReboot(const std::string_view arg) {
|
||||
LOGN(HELPER, INFO) << "reboot request sent!!!" << std::endl;
|
||||
|
||||
unsigned cmd = ANDROID_RB_RESTART2;
|
||||
@@ -215,6 +224,37 @@ bool reboot(const std::string_view arg) {
|
||||
|
||||
return android_reboot(cmd, 0, arg.empty() ? nullptr : arg.data()) != -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t getRandomOffset(const uint64_t size, const uint64_t bufferSize) {
|
||||
if (size <= bufferSize) return 0;
|
||||
const uint64_t maxOffset = size - bufferSize;
|
||||
srand(time(nullptr));
|
||||
return rand() % maxOffset;
|
||||
}
|
||||
|
||||
int convertTo(const uint64_t size, const sizeCastTypes type) {
|
||||
if (type == KB) return TO_KB(size);
|
||||
if (type == MB) return TO_MB(size);
|
||||
if (type == GB) return TO_GB(size);
|
||||
return static_cast<int>(size);
|
||||
}
|
||||
|
||||
std::string multipleToString(const sizeCastTypes type) {
|
||||
if (type == KB) return "KB";
|
||||
if (type == MB) return "MB";
|
||||
if (type == GB) return "GB";
|
||||
return "B";
|
||||
}
|
||||
|
||||
std::string format(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
char str[1024];
|
||||
vsnprintf(str, sizeof(str), format, args);
|
||||
va_end(args);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string getLibVersion() { MKVERSION("libhelper"); }
|
||||
} // namespace Helper
|
||||
|
||||
@@ -28,7 +28,7 @@ std::string test_path(const char *file) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) return 2;
|
||||
else TEST_DIR = argv[1];
|
||||
TEST_DIR = argv[1];
|
||||
|
||||
try {
|
||||
std::cout << "Has super user?; " << std::boolalpha << Helper::hasSuperUser()
|
||||
@@ -50,11 +50,11 @@ int main(int argc, char **argv) {
|
||||
<< std::endl;
|
||||
|
||||
if (!Helper::writeFile("file.txt", "hello world"))
|
||||
throw Helper::Error("Cannor write \"hello world\" in 'file.txt'");
|
||||
throw Helper::Error("Cannot 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'");
|
||||
if (const auto content = Helper::readFile("file.txt"); !content)
|
||||
throw Helper::Error("Cannot read 'file.txt'");
|
||||
else std::cout << "'file.txt': " << *content << std::endl;
|
||||
|
||||
std::cout << "Making directory 'dir2': " << std::boolalpha
|
||||
@@ -78,8 +78,8 @@ int main(int argc, char **argv) {
|
||||
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'");
|
||||
if (const auto sha256 = Helper::sha256Of(test_path("file2.txt")); !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): "
|
||||
@@ -95,7 +95,7 @@ int main(int argc, char **argv) {
|
||||
<< Helper::runCommand("ls") << std::endl;
|
||||
std::cout << "Spawn confirm propt..." << std::endl;
|
||||
|
||||
bool p = Helper::confirmPropt("Please answer");
|
||||
const bool p = Helper::confirmPropt("Please answer");
|
||||
std::cout << "Result of confirm propt: " << std::boolalpha << p
|
||||
<< std::endl;
|
||||
|
||||
@@ -104,7 +104,7 @@ int main(int argc, char **argv) {
|
||||
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;
|
||||
<< Helper::runCommandWithOutput("ls").first << 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") << ": "
|
||||
@@ -119,13 +119,29 @@ int main(int argc, char **argv) {
|
||||
std::cout << "pathJoin() test 4: " << Helper::pathJoin("mydir", "/dir2")
|
||||
<< std::endl;
|
||||
|
||||
Helper::PureTuple<int, std::string, bool> values = {
|
||||
{1, "hi", true}, {2, "im", true}, {3, "helper", false}};
|
||||
|
||||
values.insert(std::make_tuple(0, "hi", false));
|
||||
values.insert(2, "im", true);
|
||||
values.insert({3, "helper", true});
|
||||
values.pop({3, "helper", true});
|
||||
values.pop_back();
|
||||
|
||||
std::cout << "pure tuple test: " << std::boolalpha
|
||||
<< static_cast<bool>(values.at(0)) << std::endl;
|
||||
for (const auto &[x, y, z] : values) {
|
||||
std::cout << std::boolalpha << "(" << x << ", " << y << ", " << z << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::cout << Helper::getLibVersion() << 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) {
|
||||
} catch (std::exception &err) {
|
||||
std::cout << err.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
|
||||
#include <cstdint> // for uint64_t
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <libhelper/lib.hpp>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility> // for std::pair
|
||||
|
||||
namespace PartitionMap {
|
||||
@@ -38,11 +39,19 @@ struct _entry {
|
||||
} props;
|
||||
};
|
||||
|
||||
struct _returnable_entry {
|
||||
uint64_t size;
|
||||
bool isLogical;
|
||||
};
|
||||
|
||||
using BasicInf = _returnable_entry;
|
||||
using Info = _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 {
|
||||
class basic_partition_map {
|
||||
private:
|
||||
void _resize_map();
|
||||
|
||||
@@ -52,15 +61,9 @@ 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 &&other) noexcept;
|
||||
basic_partition_map();
|
||||
~basic_partition_map();
|
||||
|
||||
@@ -80,6 +83,14 @@ public:
|
||||
|
||||
bool operator==(const basic_partition_map &other) const;
|
||||
bool operator!=(const basic_partition_map &other) const;
|
||||
bool operator!() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
Info operator[](int index) const;
|
||||
BasicInf operator[](const std::string_view &name) const;
|
||||
|
||||
explicit operator std::vector<Info>() const;
|
||||
explicit operator int() const;
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
@@ -118,6 +129,7 @@ public:
|
||||
[[nodiscard]] constant_iterator cend() const;
|
||||
};
|
||||
|
||||
using Partition_t = _entry;
|
||||
using Map_t = basic_partition_map;
|
||||
|
||||
class basic_partition_map_builder final {
|
||||
@@ -147,9 +159,13 @@ public:
|
||||
*/
|
||||
explicit basic_partition_map_builder(std::string_view path);
|
||||
|
||||
/**
|
||||
* Move constructor
|
||||
*/
|
||||
basic_partition_map_builder(basic_partition_map_builder &&other) noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current list content in Map_t type.
|
||||
* If no list is created, returns std::nullopt.
|
||||
*/
|
||||
[[nodiscard]] Map_t getAll() const;
|
||||
|
||||
@@ -211,6 +227,11 @@ public:
|
||||
*/
|
||||
[[nodiscard]] bool hasPartition(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* Returns true if the device has dynamic partitions, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool hasLogicalPartitions() const;
|
||||
|
||||
/**
|
||||
* Returns the bool type status of whether the
|
||||
* entered partition name is marked as logical in the
|
||||
@@ -220,11 +241,51 @@ public:
|
||||
*/
|
||||
[[nodiscard]] bool isLogical(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* Copy partition list to vec, current vec contents are cleaned
|
||||
*/
|
||||
bool copyPartitionsToVector(std::vector<std::string> &vec) const;
|
||||
|
||||
/**
|
||||
* Copy logical partition list to vec, current vec contents are cleaned
|
||||
*/
|
||||
bool copyLogicalPartitionsToVector(std::vector<std::string> &vec) const;
|
||||
|
||||
/**
|
||||
* Copy physical partition list to vec, current vec contents are cleaned
|
||||
*/
|
||||
bool copyPhysicalPartitionsToVector(std::vector<std::string> &vec) const;
|
||||
|
||||
/**
|
||||
* The created list and the current search index name are cleared.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Do input function (lambda) for all partitions.
|
||||
*/
|
||||
bool doForAllPartitions(
|
||||
const std::function<bool(std::string, BasicInf)> &func) const;
|
||||
|
||||
/**
|
||||
* Do input function (lambda) for physical partitions.
|
||||
*/
|
||||
bool doForPhysicalPartitions(
|
||||
const std::function<bool(std::string, BasicInf)> &func) const;
|
||||
|
||||
/**
|
||||
* Do input function (lambda) for logical partitions.
|
||||
*/
|
||||
bool doForLogicalPartitions(
|
||||
const std::function<bool(std::string, BasicInf)> &func) const;
|
||||
|
||||
/**
|
||||
* Do input function (lambda) for input partition list.
|
||||
*/
|
||||
bool doForPartitionList(
|
||||
const std::vector<std::string> &partitions,
|
||||
const std::function<bool(std::string, BasicInf)> &func) const;
|
||||
|
||||
/**
|
||||
* The entered path is defined as the new search
|
||||
* directory and the search is performed in the entered
|
||||
@@ -282,6 +343,41 @@ public:
|
||||
* Build map with input path. Implementation of readDirectory().
|
||||
*/
|
||||
bool operator()(std::string_view path);
|
||||
|
||||
/**
|
||||
* Get Map_t object reference
|
||||
*/
|
||||
Map_t &operator*();
|
||||
|
||||
/**
|
||||
* Get constant Map_t object reference
|
||||
*/
|
||||
const Map_t &operator*() const;
|
||||
|
||||
/**
|
||||
* Get Info structure with given index
|
||||
*/
|
||||
Info operator[](int index) const;
|
||||
|
||||
/**
|
||||
* Get BasicInfo structure with given index
|
||||
*/
|
||||
BasicInf operator[](const std::string_view &name) const;
|
||||
|
||||
/**
|
||||
* Get map contents as vector (PartitionManager::Info type).
|
||||
*/
|
||||
[[nodiscard]] explicit operator std::vector<Info>() const;
|
||||
|
||||
/**
|
||||
* Get total partition count in map (int type).
|
||||
*/
|
||||
[[nodiscard]] explicit operator int() const;
|
||||
|
||||
/**
|
||||
* Get current working directory.
|
||||
*/
|
||||
[[nodiscard]] explicit operator std::string() const;
|
||||
};
|
||||
|
||||
using Error = Helper::Error;
|
||||
@@ -321,9 +417,9 @@ constexpr uint64_t ELF =
|
||||
constexpr uint64_t RAW = 0x00000000;
|
||||
} // namespace AndroidMagic
|
||||
|
||||
extern std::unordered_map<uint64_t, std::string> FileSystemMagicMap;
|
||||
extern std::unordered_map<uint64_t, std::string> AndroidMagicMap;
|
||||
extern std::unordered_map<uint64_t, std::string> MagicMap;
|
||||
extern std::map<uint64_t, std::string> FileSystemMagicMap;
|
||||
extern std::map<uint64_t, std::string> AndroidMagicMap;
|
||||
extern std::map<uint64_t, std::string> MagicMap;
|
||||
|
||||
size_t getMagicLength(uint64_t magic);
|
||||
bool hasMagic(uint64_t magic, ssize_t buf, const std::string &path);
|
||||
@@ -333,4 +429,7 @@ std::string formatMagic(uint64_t magic);
|
||||
|
||||
#define MAP "libpartition_map"
|
||||
|
||||
#define COMMON_LAMBDA_PARAMS \
|
||||
(const std::string &partition, const PartitionMap::BasicInf props)
|
||||
|
||||
#endif // #ifndef LIBPARTITION_MAP_LIB_HPP
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
#include <fcntl.h>
|
||||
#include <libhelper/lib.hpp>
|
||||
#include <libpartition_map/lib.hpp>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "PartitionManager/PartitionManager.hpp"
|
||||
|
||||
namespace PartitionMap::Extras {
|
||||
std::unordered_map<uint64_t, std::string> FileSystemMagicMap = {
|
||||
std::map<uint64_t, std::string> FileSystemMagicMap = {
|
||||
{FileSystemMagic::EXTFS_FS, "EXT2/3/4"},
|
||||
{FileSystemMagic::F2FS_FS, "F2FS"},
|
||||
{FileSystemMagic::EROFS_FS, "EROFS"},
|
||||
@@ -36,7 +36,7 @@ std::unordered_map<uint64_t, std::string> FileSystemMagicMap = {
|
||||
{FileSystemMagic::NTFS_FS, "NTFS"},
|
||||
{FileSystemMagic::MSDOS_FS, "MSDOS"}};
|
||||
|
||||
std::unordered_map<uint64_t, std::string> AndroidMagicMap = {
|
||||
std::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)"},
|
||||
@@ -47,7 +47,7 @@ std::unordered_map<uint64_t, std::string> AndroidMagicMap = {
|
||||
{AndroidMagic::ELF, "ELF"},
|
||||
{AndroidMagic::RAW, "Raw Data"}};
|
||||
|
||||
std::unordered_map<uint64_t, std::string> MagicMap = {
|
||||
std::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)"},
|
||||
@@ -89,7 +89,7 @@ bool hasMagic(const uint64_t magic, const ssize_t buf,
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *buffer = new uint8_t[buf];
|
||||
auto *buffer = new (std::nothrow) uint8_t[buf];
|
||||
collector.delAfterProgress(buffer);
|
||||
|
||||
const ssize_t bytesRead = read(fd, buffer, buf);
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <filesystem>
|
||||
#ifndef ANDROID_BUILD
|
||||
#include <generated/buildInfo.hpp>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <libpartition_map/lib.hpp>
|
||||
#include <linux/fs.h>
|
||||
@@ -47,7 +49,13 @@ bool basic_partition_map_builder::_is_real_block_dir(
|
||||
}
|
||||
|
||||
Map_t basic_partition_map_builder::_build_map(std::string_view path,
|
||||
bool logical) {
|
||||
const bool logical) {
|
||||
if (!Helper::directoryIsExists(path) && logical) {
|
||||
LOGN(MAP, WARNING) << "This device not contains logical partitions."
|
||||
<< std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
Map_t map;
|
||||
std::vector<std::filesystem::directory_entry> entries{
|
||||
std::filesystem::directory_iterator(path),
|
||||
@@ -57,8 +65,8 @@ Map_t basic_partition_map_builder::_build_map(std::string_view path,
|
||||
});
|
||||
|
||||
LOGN_IF(MAP, WARNING, entries.empty())
|
||||
<< "" << path
|
||||
<< "is exists but generated vector is empty "
|
||||
<< path
|
||||
<< " is exists but generated vector is empty "
|
||||
"(std::vector<std::filesystem::directory_entry>)."
|
||||
<< std::endl;
|
||||
for (const auto &entry : entries) {
|
||||
@@ -79,6 +87,9 @@ void basic_partition_map_builder::_insert_logicals(Map_t &&logicals) {
|
||||
<< "merging created logical partition list to this object's variable."
|
||||
<< std::endl;
|
||||
_current_map.merge(logicals);
|
||||
LOGN(MAP, INFO) << "Cleaning created logical partition because not need more."
|
||||
<< std::endl;
|
||||
logicals.clear();
|
||||
}
|
||||
|
||||
void basic_partition_map_builder::_map_build_check() const {
|
||||
@@ -125,8 +136,7 @@ basic_partition_map_builder::basic_partition_map_builder() {
|
||||
LOGN(MAP, ERROR) << "Cannot build map by any default search entry."
|
||||
<< std::endl;
|
||||
|
||||
LOGN(MAP, INFO) << "default constructor successfully ended work."
|
||||
<< std::endl;
|
||||
LOGN(MAP, INFO) << "default constructor ended work." << std::endl;
|
||||
_insert_logicals(_build_map("/dev/block/mapper", true));
|
||||
_map_builded = true;
|
||||
}
|
||||
@@ -151,12 +161,29 @@ basic_partition_map_builder::basic_partition_map_builder(
|
||||
_map_builded = true;
|
||||
}
|
||||
|
||||
basic_partition_map_builder::basic_partition_map_builder(
|
||||
basic_partition_map_builder &&other) noexcept {
|
||||
_current_map = Map_t(std::move(other._current_map));
|
||||
_workdir = std::move(other._workdir);
|
||||
_any_generating_error = other._any_generating_error;
|
||||
_map_builded = other._map_builded;
|
||||
other.clear();
|
||||
}
|
||||
|
||||
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::hasLogicalPartitions() const {
|
||||
_map_build_check();
|
||||
for (const auto &[name, props] : _current_map)
|
||||
if (props.isLogical) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::isLogical(const std::string_view name) const {
|
||||
_map_build_check();
|
||||
return _current_map.is_logical(name);
|
||||
@@ -183,7 +210,7 @@ bool basic_partition_map_builder::readDirectory(const std::string_view path) {
|
||||
throw Error("Cannot find directory: %s. Cannot build partition map!",
|
||||
path.data());
|
||||
|
||||
LOGN(MAP, INFO) << "read " << path << " successfull." << std::endl;
|
||||
LOGN(MAP, INFO) << "read " << path << " successfully." << std::endl;
|
||||
_insert_logicals(_build_map("/dev/block/mapper", true));
|
||||
_map_builded = true;
|
||||
return true;
|
||||
@@ -210,17 +237,148 @@ bool basic_partition_map_builder::readDefaultDirectories() {
|
||||
LOGN(MAP, ERROR) << "Cannot build map by any default search entry."
|
||||
<< std::endl;
|
||||
|
||||
LOGN(MAP, INFO) << "read default directories successfull." << std::endl;
|
||||
LOGN(MAP, INFO) << "read default directories successfully." << std::endl;
|
||||
_insert_logicals(_build_map("/dev/block/mapper", true));
|
||||
_map_builded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::copyPartitionsToVector(
|
||||
std::vector<std::string> &vec) const {
|
||||
if (_current_map.empty()) {
|
||||
LOGN(MAP, ERROR) << "Current map is empty.";
|
||||
return false;
|
||||
}
|
||||
vec.clear();
|
||||
for (const auto &[name, props] : _current_map)
|
||||
vec.push_back(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::copyLogicalPartitionsToVector(
|
||||
std::vector<std::string> &vec) const {
|
||||
if (_current_map.empty()) {
|
||||
LOGN(MAP, ERROR) << "Current map is empty.";
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> vec2;
|
||||
for (const auto &[name, props] : _current_map)
|
||||
if (props.isLogical) vec2.push_back(name);
|
||||
|
||||
if (vec2.empty()) {
|
||||
LOGN(MAP, ERROR) << "Cannot find logical partitions in current map.";
|
||||
return false;
|
||||
} else vec = vec2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::copyPhysicalPartitionsToVector(
|
||||
std::vector<std::string> &vec) const {
|
||||
if (_current_map.empty()) {
|
||||
LOGN(MAP, ERROR) << "Current map is empty.";
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> vec2;
|
||||
for (const auto &[name, props] : _current_map)
|
||||
if (!props.isLogical) vec2.push_back(name);
|
||||
|
||||
if (vec2.empty()) {
|
||||
LOGN(MAP, ERROR) << "Cannot find physical partitions in current map.";
|
||||
return false;
|
||||
} else vec = vec2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::empty() const {
|
||||
_map_build_check();
|
||||
return _current_map.empty();
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::doForAllPartitions(
|
||||
const std::function<bool(std::string, BasicInf)> &func) const {
|
||||
_map_build_check();
|
||||
bool err = false;
|
||||
|
||||
LOGN(MAP, INFO) << "Doing input function for all partitions." << std::endl;
|
||||
for (const auto &[name, props] : _current_map) {
|
||||
if (func(name, {props.size, props.isLogical}))
|
||||
LOGN(MAP, INFO) << "Done progress for " << name << " partition."
|
||||
<< std::endl;
|
||||
else {
|
||||
err = true;
|
||||
LOGN(MAP, ERROR) << "Failed progress for " << name << " partition."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::doForPhysicalPartitions(
|
||||
const std::function<bool(std::string, BasicInf)> &func) const {
|
||||
_map_build_check();
|
||||
bool err = false;
|
||||
|
||||
LOGN(MAP, INFO) << "Doing input function for physical partitions."
|
||||
<< std::endl;
|
||||
for (const auto &[name, props] : _current_map) {
|
||||
if (props.isLogical) continue;
|
||||
if (func(name, {props.size, props.isLogical}))
|
||||
LOGN(MAP, INFO) << "Done progress for " << name << " partition."
|
||||
<< std::endl;
|
||||
else {
|
||||
err = true;
|
||||
LOGN(MAP, ERROR) << "Failed progress for " << name << " partition."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::doForLogicalPartitions(
|
||||
const std::function<bool(std::string, BasicInf)> &func) const {
|
||||
_map_build_check();
|
||||
bool err = false;
|
||||
|
||||
LOGN(MAP, INFO) << "Doing input function for logical partitions."
|
||||
<< std::endl;
|
||||
for (const auto &[name, props] : _current_map) {
|
||||
if (!props.isLogical) continue;
|
||||
if (func(name, {props.size, props.isLogical}))
|
||||
LOGN(MAP, INFO) << "Done progress for " << name << " partition."
|
||||
<< std::endl;
|
||||
else {
|
||||
err = true;
|
||||
LOGN(MAP, ERROR) << "Failed progress for " << name << " partition."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool basic_partition_map_builder::doForPartitionList(
|
||||
const std::vector<std::string> &partitions,
|
||||
const std::function<bool(std::string, BasicInf)> &func) const {
|
||||
_map_build_check();
|
||||
bool err = false;
|
||||
|
||||
LOGN(MAP, INFO) << "Doing input function for input partition list."
|
||||
<< std::endl;
|
||||
for (const auto &partition : partitions) {
|
||||
if (!hasPartition(partition))
|
||||
throw Error("Couldn't find partition: %s", partition.data());
|
||||
if (!func(partition, _current_map[partition])) {
|
||||
err = true;
|
||||
LOGN(MAP, ERROR) << "Failed progress for " << partition << " partition."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
basic_partition_map_builder::sizeOf(const std::string_view name) const {
|
||||
_map_build_check();
|
||||
@@ -251,5 +409,30 @@ bool basic_partition_map_builder::operator()(const std::string_view path) {
|
||||
return readDirectory(path);
|
||||
}
|
||||
|
||||
Map_t &basic_partition_map_builder::operator*() { return _current_map; }
|
||||
|
||||
const Map_t &basic_partition_map_builder::operator*() const {
|
||||
return _current_map;
|
||||
}
|
||||
|
||||
Info basic_partition_map_builder::operator[](const int index) const {
|
||||
return _current_map[index];
|
||||
}
|
||||
|
||||
BasicInf
|
||||
basic_partition_map_builder::operator[](const std::string_view &name) const {
|
||||
return _current_map[name];
|
||||
}
|
||||
|
||||
basic_partition_map_builder::operator std::vector<Info>() const {
|
||||
return static_cast<std::vector<Info>>(_current_map);
|
||||
}
|
||||
|
||||
basic_partition_map_builder::operator int() const {
|
||||
return static_cast<int>(_current_map);
|
||||
}
|
||||
|
||||
basic_partition_map_builder::operator std::string() const { return _workdir; }
|
||||
|
||||
std::string getLibVersion() { MKVERSION("libpartition_map"); }
|
||||
} // namespace PartitionMap
|
||||
|
||||
@@ -116,6 +116,13 @@ basic_partition_map::basic_partition_map(const basic_partition_map &other)
|
||||
std::copy(other._data, other._data + _count, _data);
|
||||
}
|
||||
|
||||
basic_partition_map::basic_partition_map(basic_partition_map &&other) noexcept
|
||||
: _data(new _entry[other._capacity]), _count(other._count),
|
||||
_capacity(other._capacity) {
|
||||
std::copy(other._data, other._data + _count, _data);
|
||||
other.clear();
|
||||
}
|
||||
|
||||
basic_partition_map::basic_partition_map() : _capacity(6) {
|
||||
_data = new _entry[_capacity];
|
||||
}
|
||||
@@ -155,7 +162,7 @@ bool basic_partition_map::is_logical(const std::string_view name) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
basic_partition_map::_returnable_entry
|
||||
_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};
|
||||
@@ -177,13 +184,10 @@ std::string basic_partition_map::find_(const std::string &name) const {
|
||||
|
||||
size_t basic_partition_map::size() const { return _count; }
|
||||
|
||||
bool basic_partition_map::empty() const {
|
||||
if (_count > 0) return false;
|
||||
return true;
|
||||
}
|
||||
bool basic_partition_map::empty() const { return _count == 0; }
|
||||
|
||||
void basic_partition_map::clear() {
|
||||
LOGN(MAP, INFO) << "map clean requested. Map is empty now." << std::endl;
|
||||
LOGN(MAP, INFO) << "map clean requested. Cleaning..." << std::endl;
|
||||
delete[] _data;
|
||||
_count = 0;
|
||||
_capacity = 6;
|
||||
@@ -222,6 +226,35 @@ bool basic_partition_map::operator!=(const basic_partition_map &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
basic_partition_map::operator bool() const { return _count > 0; }
|
||||
|
||||
bool basic_partition_map::operator!() const { return _count == 0; }
|
||||
|
||||
Info basic_partition_map::operator[](const int index) const {
|
||||
if (_count == 0 || index >= _count) return {};
|
||||
return _data[index];
|
||||
}
|
||||
|
||||
BasicInf basic_partition_map::operator[](const std::string_view &name) const {
|
||||
if (_count == 0) return {};
|
||||
|
||||
if (const int i = _index_of(name); name == _data[i].name)
|
||||
return {_data[i].props.size, _data[i].props.isLogical};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
basic_partition_map::operator std::vector<Info>() const {
|
||||
std::vector<Info> v;
|
||||
if (_count == 0) return {};
|
||||
for (size_t i = 0; i < _count; i++)
|
||||
v.push_back(
|
||||
{_data[i].name, {_data[i].props.size, _data[i].props.isLogical}});
|
||||
return v;
|
||||
}
|
||||
|
||||
basic_partition_map::operator int() const { return static_cast<int>(_count); }
|
||||
|
||||
basic_partition_map::iterator basic_partition_map::begin() const {
|
||||
return iterator(_data);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <libpartition_map/lib.hpp>
|
||||
#include <unistd.h>
|
||||
@@ -54,10 +55,30 @@ int main() {
|
||||
for (const auto &name : *physicals)
|
||||
std::cout << " - " << name << std::endl;
|
||||
|
||||
if (const std::vector<PartitionMap::Info> parts =
|
||||
static_cast<std::vector<PartitionMap::Info>>(MyMap);
|
||||
parts.empty())
|
||||
throw PartitionMap::Error(
|
||||
"operator std::vector<PartitionMap::Info>() returned empty vector");
|
||||
|
||||
auto func = [](const std::string &partition,
|
||||
const PartitionMap::BasicInf props) -> bool {
|
||||
std::ofstream f("parts.txt");
|
||||
f << "Partition: " << partition << ", size: " << props.size
|
||||
<< ", logical: " << props.isLogical;
|
||||
f.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
return !f.fail();
|
||||
};
|
||||
if (!MyMap.doForAllPartitions(func))
|
||||
throw PartitionMap::Error("doForAllPartitions() progress failed");
|
||||
|
||||
std::cout << "Total partitions count: " << (int)MyMap << 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 << "Search dir test 2: " << static_cast<std::string>(MyMap)
|
||||
<< std::endl;
|
||||
std::cout << "Has partition cache? = " << MyMap.hasPartition("cache")
|
||||
<< std::endl;
|
||||
std::cout << "system partition is logical? = " << MyMap.isLogical("system")
|
||||
@@ -78,6 +99,9 @@ int main() {
|
||||
} catch (PartitionMap::Error &error) {
|
||||
std::cerr << error.what() << std::endl;
|
||||
return 1;
|
||||
} catch (std::ios_base::failure &error) {
|
||||
std::cerr << "fstream error: " << error.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user