Add ohos fixparts func

Signed-off-by: jiangqianrong <jiangqianrong1@huawei.com>
This commit is contained in:
jiangqianrong
2026-03-19 09:33:35 +08:00
parent 3725b16c78
commit 05c8ead94c
6 changed files with 579 additions and 0 deletions
+22
View File
@@ -47,3 +47,25 @@ ohos_executable("sgdisk") {
part_name = "gptfdisk"
install_images = [ "system" ]
}
ohos_executable("ohos_fixparts") {
install_enable = true
sources = [
"ohos/ohos_fixparts.cpp",
"ohos/ohos_mbr_helper.cpp",
]
sources += [
"basicmbr.cc",
"crc32.cc",
"diskio-unix.cc",
"diskio.cc",
"mbrpart.cc",
"support.cc",
]
public_configs = [ ":gptdisk_config" ]
external_deps = [
"e2fsprogs:libext2_uuid",
]
subsystem_name = "thirdparty"
part_name = "gptfdisk"
install_images = [ "system" ]
}
+3
View File
@@ -35,6 +35,9 @@
"inner_kits": [
{
"name": "//third_party/gptfdisk:sgdisk"
},
{
"name": "//third_party/gptfdisk:ohos_fixparts"
}
],
"test": []
+242
View File
@@ -0,0 +1,242 @@
/*
* Copyright (c) 2026 Huawei Device Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "ohos_fixparts.h"
#include "../support.h"
#include "../basicmbr.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <unistd.h>
#include <getopt.h>
OhosFixparts::OhosFixparts() {
}
OhosFixparts::~OhosFixparts() {
}
MbrResult OhosFixparts::ParseArgs(int argc, char* argv[], OhosFixpartsArgs& args) {
int opt;
int option_index = 0;
static struct option long_options[] = {
{"print", no_argument, nullptr, 'p'},
{"typecode", required_argument, nullptr, 't'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0}
};
while ((opt = getopt_long(argc, argv, "pt:h", long_options, &option_index)) != -1) {
switch (opt) {
case 'p':
args.printMBR = true;
break;
case 't': {
MbrResult result = ParseOption(optarg, args.partitionNum, args.typeCode);
if (result != MbrResult::SUCCESS) {
return result;
}
break;
}
case 'h':
args.showHelp = true;
ShowHelp(argv[0]);
return MbrResult::SUCCESS;
default:
ShowHelp(argv[0]);
return MbrResult::ERROR_UNKNOWN;
}
}
// Parse device path (remaining argument)
if (optind < argc) {
args.device = argv[optind];
}
// Check for extra arguments (should be exactly one device path)
if (optind + 1 < argc) {
std::cerr << "Error: Too many device paths specified" << std::endl;
ShowHelp(argv[0]);
return MbrResult::ERROR_INVALID_DEVICE;
}
// Validate device path
if (args.device.empty()) {
std::cerr << "Device path is required" << std::endl;
ShowHelp(argv[0]);
return MbrResult::ERROR_INVALID_DEVICE;
}
return MbrResult::SUCCESS;
}
MbrResult OhosFixparts::ParseOption(const std::string& option, int& partitionNum, uint8_t& typeCode) {
// Parse partition number and type code
std::string paramStr = option;
size_t colonPos = paramStr.find(':');
if (colonPos == std::string::npos || colonPos == 0 || colonPos == paramStr.length() - 1) {
std::cerr << "Invalid option format (expected partnum:typecode)" << std::endl;
return MbrResult::ERROR_INVALID_PARTITION;
}
std::string partNumStr = paramStr.substr(0, colonPos);
std::string typeCodeStr = paramStr.substr(colonPos + 1);
// Validate partition number - manual validation without exceptions
if (partNumStr.empty()) {
std::cerr << "Invalid partition number (must be a number)" << std::endl;
return MbrResult::ERROR_INVALID_PARTITION;
}
// Check if all characters are digits
for (char c : partNumStr) {
if (!isdigit(c)) {
std::cerr << "Invalid partition number (must be a pure number)" << std::endl;
return MbrResult::ERROR_INVALID_PARTITION;
}
}
// Convert to integer (safe because we validated all characters are digits)
std::istringstream iss(partNumStr);
iss >> partitionNum;
if (iss.fail() || !iss.eof()) {
std::cerr << "Invalid partition number (must be a number)" << std::endl;
return MbrResult::ERROR_INVALID_PARTITION;
}
if (partitionNum < 1 || partitionNum > 128) {
std::cerr << "Invalid partition number (must be 1-128)" << std::endl;
return MbrResult::ERROR_INVALID_PARTITION;
}
// Validate and parse type code
if (!ParseTypeCode(typeCodeStr, typeCode)) {
std::cerr << "Invalid type code (must be 0x01-0xFF)" << std::endl;
return MbrResult::ERROR_INVALID_TYPECODE;
}
return MbrResult::SUCCESS;
}
bool OhosFixparts::ParseTypeCode(const std::string& str, uint8_t& code) {
std::istringstream iss(str);
int value;
// Check if string starts with 0x/0X or contains only hex digits
bool isHex = false;
if (str.find("0x") == 0 || str.find("0X") == 0) {
isHex = true;
} else {
// Check if all characters are valid hex digits (0-9, a-f, A-F)
for (char c : str) {
if (!isxdigit(c)) {
isHex = false;
break;
}
isHex = true;
}
}
if (isHex) {
iss >> std::hex >> value;
} else {
iss >> std::dec >> value;
}
if (iss.fail()) {
return false;
}
// Validate range before conversion to prevent truncation
if (value < 0x01 || value > 0xFF) {
return false;
}
code = static_cast<uint8_t>(value);
return true;
}
int OhosFixparts::Run(const OhosFixpartsArgs& args) {
MbrResult result = helper_.LoadMbrData(args.device);
if (result != MbrResult::SUCCESS) {
std::cerr << "Failed to load MBR data: " << helper_.GetLastError() << std::endl;
return static_cast<int>(result);
}
// Print mode: display MBR partition table
if (args.printMBR) {
helper_.DisplayMBRData();
return 0;
}
// Modify mode: change partition type code
std::cout << "Changing partition " << args.partitionNum
<< " type code to 0x" << std::hex
<< static_cast<int>(args.typeCode) << std::dec << std::endl;
result = helper_.ChangePartitionType(args.partitionNum, args.typeCode);
if (result != MbrResult::SUCCESS) {
std::cerr << "Failed to change partition type: " << helper_.GetLastError() << std::endl;
return static_cast<int>(result);
}
result = helper_.SaveMbrData();
if (result != MbrResult::SUCCESS) {
std::cerr << "Failed to save MBR data: " << helper_.GetLastError() << std::endl;
return static_cast<int>(result);
}
std::cout << "Partition type code changed successfully." << std::endl;
return 0;
}
void OhosFixparts::ShowHelp(const char* programName) {
std::cout << "MBR Partition Type Code Modify" << std::endl;
std::cout << std::endl;
std::cout << "Usage (Print Mode):" << std::endl;
std::cout << " " << programName << " -p <device>" << std::endl;
std::cout << " " << programName << " --print <device>" << std::endl;
std::cout << std::endl;
std::cout << "Usage (Modify Mode):" << std::endl;
std::cout << " " << programName << " -t partnum:typecode <device>" << std::endl;
std::cout << " " << programName << " --typecode partnum:typecode <device>" << std::endl;
std::cout << std::endl;
std::cout << "Options:" << std::endl;
std::cout << " -p, --print Print MBR partition table" << std::endl;
std::cout << " -t partnum:typecode Change partition type code" << std::endl;
std::cout << " -h, --help Show this help message" << std::endl;
std::cout << std::endl;
std::cout << "Examples:" << std::endl;
std::cout << " " << programName << " -p /dev/sda" << std::endl;
std::cout << " " << programName << " -t 1:0x07 /dev/sda" << std::endl;
std::cout << " " << programName << " -t 2:0x83 /dev/sda" << std::endl;
std::cout << std::endl;
}
int main(int argc, char* argv[]) {
OhosFixparts fixparts;
OhosFixpartsArgs args;
MbrResult result = fixparts.ParseArgs(argc, argv, args);
if (result != MbrResult::SUCCESS) {
return static_cast<int>(result);
}
// If help was requested, exit successfully
if (args.showHelp) {
return 0;
}
return fixparts.Run(args);
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2026 Huawei Device Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef OHOS_FIXPARTS_H
#define OHOS_FIXPARTS_H
#include "ohos_mbr_helper.h"
#include <string>
// Command line arguments structure
struct OhosFixpartsArgs {
std::string device; // Device path
bool printMBR; // Print MBR partition table
bool showHelp; // Show help information
int partitionNum; // Partition number
uint8_t typeCode; // Type code
OhosFixpartsArgs()
: printMBR(false), showHelp(false), partitionNum(-1), typeCode(0) {}
};
// Main program class
class OhosFixparts {
public:
OhosFixparts();
~OhosFixparts();
// Parse command line arguments
MbrResult ParseArgs(int argc, char* argv[], OhosFixpartsArgs& args);
// Execute partition type code modification
int Run(const OhosFixpartsArgs& args);
// Show help information
void ShowHelp(const char* programName);
private:
OhosMbrHelper helper_;
// Parse hexadecimal type code
bool ParseTypeCode(const std::string& str, uint8_t& code);
// Parse option string (format: partnum:typecode) and validate all parameters
MbrResult ParseOption(const std::string& option, int& partitionNum, uint8_t& typeCode);
};
#endif // OHOS_FIXPARTS_H
+187
View File
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2026 Huawei Device Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "ohos_mbr_helper.h"
#include "../basicmbr.h"
#include <iostream>
#include <sstream>
#include <iomanip>
OhosMbrHelper::OhosMbrHelper()
: mbrData_(nullptr), loaded_(false) {
mbrData_ = new BasicMBRData();
}
OhosMbrHelper::~OhosMbrHelper() {
if (mbrData_ != nullptr) {
delete static_cast<BasicMBRData*>(mbrData_);
mbrData_ = nullptr;
}
}
MbrResult OhosMbrHelper::LoadMbrData(const std::string& device) {
MbrResult result = ValidateDevice(device);
if (result != MbrResult::SUCCESS) {
return result;
}
device_ = device;
result = ReadMbrFromDevice();
if (result != MbrResult::SUCCESS) {
return result;
}
result = ValidateMbrData();
if (result != MbrResult::SUCCESS) {
return result;
}
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
mbr->MakeItLegal();
loaded_ = true;
return MbrResult::SUCCESS;
}
MbrResult OhosMbrHelper::ValidateDevice(const std::string& device) {
if (device.empty()) {
SetError("Device path is empty");
return MbrResult::ERROR_INVALID_DEVICE;
}
return MbrResult::SUCCESS;
}
MbrResult OhosMbrHelper::ReadMbrFromDevice() {
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
if (!mbr->ReadMBRData(device_)) {
SetError("Failed to read MBR data from device: " + device_);
return MbrResult::ERROR_READ_FAILED;
}
return MbrResult::SUCCESS;
}
MbrResult OhosMbrHelper::ValidateMbrData() {
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
MBRValidity validity = mbr->GetValidity();
if (validity == gpt || validity == hybrid) {
SetError("Device appears to be a GPT disk, not MBR");
return MbrResult::ERROR_GPT_DISK;
}
if (validity == invalid) {
SetError("Invalid MBR data on device");
return MbrResult::ERROR_NOT_MBR_DISK;
}
return MbrResult::SUCCESS;
}
MbrResult OhosMbrHelper::ChangePartitionType(int partNum, uint8_t typeCode) {
// Check if MBR data is loaded
if (!loaded_) {
SetError("MBR data not loaded. Call LoadMbrData() first.");
return MbrResult::ERROR_READ_FAILED;
}
// Validate partition number range (1-128)
if (partNum < 1 || partNum > 128) {
std::ostringstream oss;
oss << "Invalid partition number " << partNum << " (must be 1-128)";
SetError(oss.str());
return MbrResult::ERROR_INVALID_PARTITION;
}
// Validate range before conversion to prevent truncation
if (typeCode < 0x01 || typeCode > 0xFF) {
std::ostringstream oss;
oss << "Invalid typecode " << typeCode << " (must be 0x01 - 0xFF)";
SetError(oss.str());
return MbrResult::ERROR_INVALID_TYPECODE;
}
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
// Check if partition exists and is not empty
if (mbr->GetLength(partNum - 1) == 0) {
std::ostringstream oss;
oss << "Partition " << partNum << " is empty or does not exist";
SetError(oss.str());
return MbrResult::ERROR_EMPTY_PARTITION;
}
// Set partition type code
int result = mbr->SetPartType(partNum - 1, typeCode);
if (result == 0) {
std::ostringstream oss;
oss << "Failed to set type code for partition " << partNum;
SetError(oss.str());
return MbrResult::ERROR_UNKNOWN;
}
return MbrResult::SUCCESS;
}
MbrResult OhosMbrHelper::SaveMbrData() {
if (!loaded_) {
SetError("MBR data not loaded. Call LoadMbrData() first.");
return MbrResult::ERROR_READ_FAILED;
}
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
if (!mbr->WriteMBRData()) {
SetError("Failed to write MBR data to device: " + device_);
return MbrResult::ERROR_WRITE_FAILED;
}
mbr->DiskSync();
return MbrResult::SUCCESS;
}
std::string OhosMbrHelper::GetLastError() const {
return lastError_;
}
void OhosMbrHelper::DisplayMBRData() {
if (!loaded_) {
std::cerr << "MBR data not loaded. Call LoadMbrData() first." << std::endl;
return;
}
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
std::cout << "MBR Partition Table:" << std::endl;
std::cout << " # Boot Start Sector End Sector Type Code Size" << std::endl;
for (int i = 0; i < 4; i++) {
uint64_t length = mbr->GetLength(i);
if (length > 0) {
uint8_t status = mbr->GetStatus(i);
uint8_t typeCode = mbr->GetType(i);
uint64_t firstSector = mbr->GetFirstSector(i);
std::cout << " " << (i + 1) << " ";
std::cout << (status == 0x80 ? " * " : " ");
std::cout << std::setw(12) << firstSector << " ";
std::cout << std::setw(12) << (firstSector + length - 1) << " ";
std::cout << "0x" << std::setfill('0') << std::setw(2)
<< std::hex << static_cast<int>(typeCode) << std::dec;
std::cout << std::setfill(' ') << " ";
std::cout << (length * 512 / (1024 * 1024)) << " MB" << std::endl;
}
}
}
void OhosMbrHelper::SetError(const std::string& error) {
lastError_ = error;
std::cerr << error << std::endl;
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2026 Huawei Device Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef OHOS_MBR_HELPER_H
#define OHOS_MBR_HELPER_H
#include <string>
#include <cstdint>
// MBR operation result codes
enum class MbrResult {
SUCCESS = 0,
ERROR_INVALID_DEVICE = 1,
ERROR_READ_FAILED = 2,
ERROR_WRITE_FAILED = 3,
ERROR_INVALID_PARTITION = 4,
ERROR_INVALID_TYPECODE = 5,
ERROR_NOT_MBR_DISK = 6,
ERROR_GPT_DISK = 7,
ERROR_EMPTY_PARTITION = 8,
ERROR_UNKNOWN = 100
};
// MBR partition type code modifier class
class OhosMbrHelper {
public:
OhosMbrHelper();
~OhosMbrHelper();
// Load MBR data
MbrResult LoadMbrData(const std::string& device);
// Validate device path
MbrResult ValidateDevice(const std::string& device);
// Read MBR data from device
MbrResult ReadMbrFromDevice();
// Validate MBR data
MbrResult ValidateMbrData();
// Change partition type code
// partNum: Partition number (1-128)
// typeCode: Type code (0x01-0xFF)
MbrResult ChangePartitionType(int partNum, uint8_t typeCode);
// Save MBR data to disk
MbrResult SaveMbrData();
// Display MBR partition table
void DisplayMBRData();
// Get error message
std::string GetLastError() const;
private:
void* mbrData_; // BasicMBRData object pointer
std::string lastError_;
std::string device_;
bool loaded_;
// Set error message
void SetError(const std::string& error);
};
#endif // OHOS_MBR_HELPER_H