34 Commits

Author SHA1 Message Date
62b1ff98d9 change release date 2025-08-21 09:54:23 +03:00
7b29059a8e fixup manager 2025-08-18 23:06:39 +03:00
9724bee46e pmt: change latest release date 2025-08-18 22:29:07 +03:00
366bb28612 pmt: add interrupt signal handler etc. 2025-08-18 22:24:42 +03:00
58330fddf4 pmt: use smart pointers for more safe memory 2025-08-16 20:14:05 +03:00
62b73ac91a fix looping memory test function 2025-08-15 22:47:13 +03:00
20ad64c8c5 manager: set new release date 2025-08-15 22:09:21 +03:00
6999975f6a Revert "fix memory leak"
This reverts commit 47382ebf1c.
2025-08-15 20:04:25 +03:00
54f2a48ffa Reapply "fix memory leak"
This reverts commit c3a5e97d41.
2025-08-15 20:02:45 +03:00
9391847534 Reapply "pmt: use constructor/destructor attributes insetad of class"
This reverts commit d4703df1a5.
2025-08-15 20:02:29 +03:00
bfd5a78863 noo 2025-08-15 20:02:28 +03:00
d4703df1a5 Revert "pmt: use constructor/destructor attributes insetad of class"
This reverts commit 7240cca537.
2025-08-15 17:29:28 +03:00
c3a5e97d41 Revert "fix memory leak"
This reverts commit 47382ebf1c.
2025-08-15 17:29:10 +03:00
47382ebf1c fix memory leak 2025-08-15 17:22:04 +03:00
7240cca537 pmt: use constructor/destructor attributes insetad of class 2025-08-15 16:31:09 +03:00
6a8fd5854d Add bugg report info 2025-08-15 15:53:35 +03:00
f3732ff158 Move documentation to wiki page 2025-08-15 15:30:01 +03:00
b7f5348b89 Write a installing and usage etc. 2025-08-15 12:45:28 +03:00
235402ed23 Write a installing and usage etc. 2025-08-15 12:45:15 +03:00
e17ac42e55 manager: set release date 2025-08-15 12:00:53 +03:00
1bc3b5ccef pmt: CLeanup unnecessary function: real-link-path
- real-link-path function is removed.
 - Added --real-link-path flag to real-path function for as real-link-path.
2025-08-15 11:52:03 +03:00
c3acd4b370 usage: add --json-indent-size option to usages 2025-08-14 19:50:02 +03:00
05f173e895 pmt: improve usage.md :/ 2025-08-14 19:41:41 +03:00
638ed3017e pmt: add memory test documentation 2025-08-14 19:36:16 +03:00
563e8a583e pmt: fix memory leaks, and improve info function
- Removed --no-write-test argument of memory test function
 - Fixed memory leak of memory test function
 - Improved info function with using nlohmann/json header-only library
 - Some other improvents
2025-08-14 12:56:29 +03:00
bf0df8cc83 pmt: add memory test function and some new functions to libhelper 2025-08-13 10:58:48 +03:00
0bc5f70294 pmt: reformat code and improve 2025-08-13 09:54:11 +03:00
d74f385a68 pmt: dont include new memoryTestFunction 2025-08-13 09:42:37 +03:00
23087966d6 pmt: start working for 1.1.0, first: add * operator to libpartition_map 2025-08-13 09:41:27 +03:00
7350791d04 Update manager.sh 2025-08-11 14:26:47 +03:00
5d06c804e3 Update manager.sh 2025-08-11 14:13:46 +03:00
442155b9f6 manager: fix downloading and unexpected operator error 2025-08-11 14:07:56 +03:00
a1211c91fe manager: configure as only for termux 2025-08-11 12:50:02 +03:00
f33433cfe6 manager: fix typos 2025-08-11 12:43:28 +03:00
33 changed files with 26097 additions and 590 deletions

View File

@@ -60,4 +60,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: "Read [Wiki - About Release Types](https://github.com/ShawkTeam/pmt-renovated/wiki/About-Release-Types) for getting more information."

6
.idea/editor.xml generated
View File

@@ -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" />

View File

@@ -16,7 +16,7 @@
# Project info
cmake_minimum_required(VERSION 3.10)
project(pmt VERSION 1.0.0)
project(pmt VERSION 1.1.0)
# Set compiler flags
add_compile_options(-Wall -Werror -Wno-deprecated-declarations)

View File

@@ -19,15 +19,22 @@ 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 doesnt 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).
## 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)

View File

@@ -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 dont want to worry about missing libraries, **choose the static version** matching your devices 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 youre unsure which one to pick, try the **static version** first — it works out of the box on all supported devices.

319
USAGE.md
View File

@@ -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**.
Its 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 devices 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 phones 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)

View File

@@ -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;

21
include/LICENSE.nlohmann Normal file
View 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.

View File

@@ -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>
@@ -58,9 +58,8 @@ public:
class basic_variables final {
public:
basic_variables();
~basic_variables();
PartitionMap::BuildMap *PartMap;
std::unique_ptr<PartitionMap::BuildMap> PartMap;
std::string searchPath, logFile;
bool onLogical;
@@ -70,23 +69,12 @@ public:
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;
extern std::unique_ptr<VariableTable> Variables;
int Main(int argc, char **argv);
@@ -111,7 +99,7 @@ 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();
@@ -119,4 +107,4 @@ std::string getAppVersion(); // Not Android app version (an Android app is
// planned!), tells pmt version.
} // namespace PartitionManager
#endif // #ifndef LIBPMT_LIB_HPP
#endif // #ifndef LIBPMT_LIB_HPP

25526
include/nlohmann/json.hpp Normal file

File diff suppressed because it is too large Load Diff

View 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_

View File

@@ -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

View File

@@ -22,9 +22,9 @@ set(PMT_SOURCES
${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
)

View File

@@ -39,12 +39,20 @@ 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 (Variables->PartMap->hasPartition(entry) &&
Variables->PartMap->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 = Variables->PartMap->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;
}
}
}

View File

@@ -16,45 +16,58 @@
#include "functions/functions.hpp"
#include <PartitionManager/PartitionManager.hpp>
#include <unistd.h>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <csignal>
#include <generated/buildInfo.hpp>
#include <string>
#include <unistd.h>
namespace PartitionManager {
variableProtect protector;
auto Variables = new VariableTable();
variableProtect::variableProtect() {
__attribute__((constructor))
void init() {
Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log");
}
variableProtect::~variableProtect() { delete _ptr; }
void variableProtect::setVariablePointer(basic_variables *&_ptr) {
this->_ptr = _ptr;
static void sigHandler(const int sig) {
// Even if only SIGINT is to be captured for now, this is still a more appropriate code
if (sig == SIGINT) println("\n%sInterrupted.%s", YELLOW, STYLE_RESET);
exit(sig);
}
basic_variables::~basic_variables() { delete PartMap; }
auto Variables = std::make_unique<VariableTable>();
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 &) {
}
}
int Main(int argc, char **argv) {
try {
// try-catch start
if (argc < 2) {
println(
"Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.",
argv[0]);
return EXIT_FAILURE;
}
signal(SIGINT, sigHandler);
CLI::App AppMain{"Partition Manager Tool"};
protector.setVariablePointer(Variables);
FunctionManager FuncManager;
AppMain.fallthrough(true);
AppMain.set_help_all_flag("--help-all", "Print full help message and exit");
AppMain.footer("Partition Manager Tool is written by YZBruh\nThis project "
"licensed under "
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
@@ -62,7 +75,7 @@ int Main(int argc, char **argv) {
"Set partition search path")
->check([&](const std::string &val) {
if (val.find("/block") == std::string::npos)
throw CLI::ValidationError(
return std::string(
"Partition search path is unexpected! Couldn't find "
"'block' in input path!");
return std::string();
@@ -80,13 +93,6 @@ int Main(int argc, char **argv) {
AppMain.add_flag("-v,--version", Variables->viewVersion,
"Print version and exit");
if (argc < 2) {
println(
"Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.",
argv[0]);
return EXIT_FAILURE;
}
FuncManager.registerFunction(std::make_unique<backupFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<flashFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain);
@@ -94,10 +100,10 @@ int Main(int argc, char **argv) {
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);
FuncManager.registerFunction(std::make_unique<memoryTestFunction>(),
AppMain);
CLI11_PARSE(AppMain, argc, argv);
@@ -115,7 +121,9 @@ int Main(int argc, char **argv) {
"(--search-path)");
if (!Helper::hasSuperUser()) {
if (!(FuncManager.isUsed("rebootFunction") && Helper::hasAdbPermissions()))
if (!((FuncManager.isUsed("rebootFunction") &&
Helper::hasAdbPermissions()) ||
FuncManager.isUsed("memoryTestFunction")))
throw Error(
"Partition Manager Tool is requires super-user privileges!\n");
}

View File

@@ -28,7 +28,8 @@
namespace PartitionManager {
pair backupFunction::runAsync(const std::string &partitionName,
const std::string &outputName, int bufferSize) {
const std::string &outputName,
const uint64_t bufferSize) {
if (!Variables->PartMap->hasPartition(partitionName))
return {format("Couldn't find partition: %s", partitionName.data()), false};
@@ -53,7 +54,6 @@ pair backupFunction::runAsync(const std::string &partitionName,
outputName.data()),
false};
setupBufferSize(bufferSize, partitionName);
LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName
<< "): " << bufferSize << std::endl;
@@ -76,7 +76,7 @@ pair backupFunction::runAsync(const std::string &partitionName,
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);
@@ -94,7 +94,7 @@ 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"
@@ -115,9 +115,10 @@ 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;
}
@@ -131,13 +132,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;
}

View File

@@ -25,7 +25,8 @@ Copyright 2025 Yağız Zengin
#define EFUN "eraseFunction"
namespace PartitionManager {
pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
pair eraseFunction::runAsync(const std::string &partitionName,
const uint64_t bufferSize) {
if (!Variables->PartMap->hasPartition(partitionName))
return {format("Couldn't find partition: %s", partitionName.data()), false};
@@ -42,7 +43,6 @@ pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
false};
}
setupBufferSize(bufferSize, partitionName);
LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize;
// Automatically close file descriptors and delete allocated memories (arrays)
@@ -63,7 +63,7 @@ pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
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);
@@ -94,15 +94,19 @@ bool eraseFunction::init(CLI::App &_app) {
->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() {
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;
}

View File

@@ -26,7 +26,8 @@ Copyright 2025 Yağız Zengin
namespace PartitionManager {
pair flashFunction::runAsync(const std::string &partitionName,
const std::string &imageName, int bufferSize) {
const std::string &imageName,
const uint64_t bufferSize) {
if (!Helper::fileIsExists(imageName))
return {format("Couldn't find image file: %s", imageName.data()), false};
if (!Variables->PartMap->hasPartition(partitionName))
@@ -52,8 +53,7 @@ pair flashFunction::runAsync(const std::string &partitionName,
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;
@@ -74,7 +74,7 @@ pair flashFunction::runAsync(const std::string &partitionName,
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);
@@ -100,8 +100,10 @@ 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)");
@@ -115,13 +117,17 @@ bool flashFunction::run() {
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));
LOGN(FFUN, INFO) << "Created thread for flashing image to " << partitions[i]
<< std::endl;
}

View File

@@ -19,7 +19,7 @@ Copyright 2025 Yağız Zengin
#include <cerrno>
#include <cstdlib>
#include <fcntl.h>
#include <unistd.h>
#include <nlohmann/json.hpp>
#define IFUN "infoFunction"
@@ -36,13 +36,20 @@ bool infoFunction::init(CLI::App &_app) {
->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_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;
}
@@ -59,6 +66,7 @@ bool infoFunction::run() {
partitions.push_back(name);
}
std::vector<PartitionMap::Partition_t> jParts;
for (const auto &partition : partitions) {
if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data());
@@ -75,14 +83,9 @@ 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,
{Variables->PartMap->sizeOf(partition),
Variables->PartMap->isLogical(partition)}});
else
#ifdef __LP64__
println("partition=%s size=%lu isLogical=%s",
@@ -93,6 +96,18 @@ bool infoFunction::run() {
Variables->PartMap->isLogical(partition) ? "true" : "false");
}
if (jsonFormat) {
nlohmann::json j;
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;
}

View File

@@ -0,0 +1,130 @@
/*
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"
namespace PartitionManager {
bool memoryTestFunction::init(CLI::App &_app) {
LOGN(MTFUN, INFO) << "Initializing variables of memory test function."
<< std::endl;
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;
}
bool memoryTestFunction::run() {
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);
std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution dist(0, 255);
for (size_t i = 0; i < bufferSize; i++)
buffer[i] = static_cast<char>(dist(rng));
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\n", 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\n", 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\n", 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;
}
bool memoryTestFunction::isUsed() const { return cmd->parsed(); }
const char *memoryTestFunction::name() const { return MTFUN; }
} // namespace PartitionManager

View File

@@ -36,16 +36,21 @@ bool partitionSizeFunction::init(CLI::App &_app) {
->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(false);
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;
}

View File

@@ -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

View File

@@ -27,6 +27,7 @@ bool realPathFunction::init(CLI::App &_app) {
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;
}
@@ -46,7 +47,10 @@ bool realPathFunction::run() {
partition.data());
}
println("%s", Variables->PartMap->getRealPathOf(partition).data());
if (realLinkPath)
println("%s", Variables->PartMap->getRealLinkPathOf(partition).data());
else
println("%s", Variables->PartMap->getRealPathOf(partition).data());
}
return true;

View File

@@ -27,11 +27,15 @@ bool typeFunction::init(CLI::App &_app) {
->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;
}
@@ -52,7 +56,7 @@ bool typeFunction::run() {
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))) {

View File

@@ -29,7 +29,7 @@ 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;
@@ -37,7 +37,7 @@ public:
bool init(CLI::App &_app) override;
bool run() override;
static pair runAsync(const std::string &partitionName,
const std::string &outputName, int bufferSize);
const std::string &outputName, uint64_t bufferSize);
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
@@ -48,7 +48,7 @@ class flashFunction final : public FunctionBase {
private:
std::vector<std::string> partitions, imageNames;
std::string rawPartitions, rawImageNames, imageDirectory;
int bufferSize = 4096;
uint64_t bufferSize = 0;
public:
CLI::App *cmd = nullptr;
@@ -56,7 +56,7 @@ public:
bool init(CLI::App &_app) override;
bool run() override;
static pair runAsync(const std::string &partitionName,
const std::string &imageName, int bufferSize);
const std::string &imageName, uint64_t bufferSize);
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
@@ -66,14 +66,14 @@ public:
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);
static pair runAsync(const std::string &partitionName, uint64_t bufferSize);
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
@@ -100,8 +100,8 @@ public:
class infoFunction final : public FunctionBase {
private:
std::vector<std::string> partitions;
std::string jNamePartition = "name", jNameSize = "size",
jNameLogical = "isLogical";
std::string jNamePartition, jNameSize, jNameLogical;
int jIndentSize = 2;
bool jsonFormat = false;
public:
@@ -117,20 +117,7 @@ public:
class realPathFunction 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;
};
class realLinkPathFunction final : public FunctionBase {
private:
std::vector<std::string> partitions;
bool realLinkPath = false;
public:
CLI::App *cmd = nullptr;
@@ -146,7 +133,7 @@ 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;
@@ -171,6 +158,23 @@ public:
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
};
class memoryTestFunction final : public FunctionBase {
private:
uint64_t bufferSize = MB(4), /* bufferSizeRandom = KB(4),*/ testFileSize = 0;
std::string testPath;
bool doNotReadTest = 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;
};
} // namespace PartitionManager
#endif // #ifndef FUNCTIONS_HPP

View File

@@ -81,12 +81,14 @@ private:
std::vector<uint8_t *> _ptrs_u;
std::vector<FILE *> _fps;
std::vector<int> _fds;
std::vector<std::string> _files;
public:
~garbageCollector();
void delAfterProgress(char *&_ptr);
void delAfterProgress(uint8_t *&_ptr);
void delFileAfterProgress(const std::string& path);
void closeAfterProgress(FILE *&_fp);
void closeAfterProgress(int _fd);
};
@@ -151,6 +153,7 @@ std::string runCommandWithOutput(std::string_view cmd);
std::string pathJoin(std::string base, std::string relative);
std::string pathBasename(std::string_view entry);
std::string pathDirname(std::string_view entry);
uint64_t getRandomOffset(uint64_t size, uint64_t bufferSize);
// Android
std::string getProperty(std::string_view prop);

View File

@@ -95,6 +95,8 @@ garbageCollector::~garbageCollector() {
close(fd);
for (const auto &fp : _fps)
fclose(fp);
for (const auto &file : _files)
eraseEntry(file);
}
void garbageCollector::delAfterProgress(char *&_ptr) {
@@ -103,6 +105,9 @@ void garbageCollector::delAfterProgress(char *&_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);
}

View File

@@ -216,5 +216,11 @@ bool reboot(const std::string_view arg) {
return android_reboot(cmd, 0, arg.empty() ? nullptr : arg.data()) != -1;
}
uint64_t getRandomOffset(const uint64_t size, const uint64_t bufferSize) {
if (size <= bufferSize) return 0;
const uint64_t maxOffset = size - bufferSize;
return rand() % maxOffset;
}
std::string getLibVersion() { MKVERSION("libhelper"); }
} // namespace Helper

View File

@@ -42,7 +42,7 @@ struct _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();
@@ -118,6 +118,7 @@ public:
[[nodiscard]] constant_iterator cend() const;
};
using Partition_t = _entry;
using Map_t = basic_partition_map;
class basic_partition_map_builder final {
@@ -282,6 +283,12 @@ public:
* Build map with input path. Implementation of readDirectory().
*/
bool operator()(std::string_view path);
/**
* Get Map_t object reference
*/
Map_t &operator*();
const Map_t &operator*() const;
};
using Error = Helper::Error;

View File

@@ -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);

View File

@@ -47,7 +47,7 @@ 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) {
Map_t map;
std::vector<std::filesystem::directory_entry> entries{
std::filesystem::directory_iterator(path),
@@ -251,5 +251,11 @@ 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;
}
std::string getLibVersion() { MKVERSION("libpartition_map"); }
} // namespace PartitionMap