Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance BMAP parsing #19

Merged
merged 2 commits into from
Feb 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion bmap-writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ struct range_t {

struct bmap_t {
std::vector<range_t> ranges;
std::string checksumType;
size_t blockSize;
size_t blocksTotal;
size_t blocksMapped;
std::string bmapVersion;
std::string bmapChecksum;
};

int parseBMap(const std::string &filename, bmap_t& bmapData) {
Expand All @@ -70,15 +75,53 @@ int parseBMap(const std::string &filename, bmap_t& bmapData) {
throw std::string("BMAP file is invalid");
}

// Store BMAP version
bmapData.bmapVersion = p_root->Attribute("version");

// Parse image information
tinyxml2::XMLElement * p_data;

p_data = p_root->FirstChildElement("BlocksCount");
if (p_data == nullptr) {
throw std::string("BMAP: BlocksCount not found");
} else {
bmapData.blocksTotal = static_cast<size_t>(std::stoul(p_data->GetText()));
}

p_data = p_root->FirstChildElement("MappedBlocksCount");
if (p_data == nullptr) {
throw std::string("BMAP: MappedBlocksCount not found");
} else {
bmapData.blocksMapped = static_cast<size_t>(std::stoul(p_data->GetText()));
}

p_data = p_root->FirstChildElement("ChecksumType");
if (p_data == nullptr) {
throw std::string("BMAP: ChecksumType not found");
} else {
for (const auto ch: std::string(p_data->GetText())) {
if (!std::isspace(ch)) {
bmapData.checksumType.push_back(static_cast<char>(std::tolower(ch)));
}
}
}

p_data = p_root->FirstChildElement("BmapFileChecksum");
if (p_data == nullptr) {
throw std::string("BMAP: BmapFileChecksum not found");
} else {
for (const auto ch: std::string(p_data->GetText())) {
if (!std::isspace(ch)) {
bmapData.bmapChecksum.push_back(static_cast<char>(ch));
}
}
}

p_data = p_root->FirstChildElement("BlockSize");
if (p_data == nullptr) {
throw std::string("BMAP: BlockSize not found");
} else {
bmapData.blockSize = static_cast<size_t>(std::stoul(p_data->GetText()));
//std::cout << "BlockSize: " << bmapData.blockSize << std::endl;
}

p_data = p_root->FirstChildElement("BlockMap");
Expand Down Expand Up @@ -129,6 +172,46 @@ int parseBMap(const std::string &filename, bmap_t& bmapData) {
return EXIT_SUCCESS;
}

int checkBmap(const std::string &filename, const std::string& checksum) {
try {
std::ifstream file(filename);
std::string line;

if (!file.is_open()) {
throw std::string("Failed to open BMAP file");
} else {
SHA256Ctx sha256Ctx = {};

while (std::getline(file, line)) {
std::size_t found = line.find(checksum);
// The actual checksum of the BMAP file shall be replaced with a set of '0'
if (found != std::string::npos) {
line = line.replace(found, checksum.size(), checksum.size(), '0');
}
// add the newline character not read by std::getline
line.push_back('\n');
sha256Update(sha256Ctx, line);
}

file.close();

std::string compChecksum = sha256Finalize(sha256Ctx);
if (compChecksum.compare(checksum) != 0) {
std::stringstream serr;
serr << "BMAP checksum invalid" << std::endl;
serr << "Computed Checksum: " << compChecksum << std::endl;
serr << "Expected Checksum: " << checksum;
throw std::string(serr.str());
}
}
} catch (const std::string& err) {
std::cerr << err << std::endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

bool isPipe(int fd) {
struct stat statbuf;
bool pipe = false;
Expand Down Expand Up @@ -430,6 +513,17 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}

if (bmap.checksumType != "sha256") {
std::cerr << "Unsupported checksum type: " << bmap.checksumType << std::endl;
return EXIT_FAILURE;
}

ret = checkBmap(bmapFile, bmap.bmapChecksum);
if (ret != 0) {
std::cerr << "BMAP file checksum failed" << std::endl;
return EXIT_FAILURE;
}

if (image_fd < 0) {
image_fd = ::open(imageFile.c_str(), O_RDONLY);
if (image_fd < 0) {
Expand All @@ -438,6 +532,14 @@ int main(int argc, char *argv[]) {
}
}

std::cout << "BMAP format version: " << bmap.bmapVersion << std::endl;
std::cout << "Image size: " << (bmap.blocksTotal * bmap.blockSize) << " bytes" << std::endl;
std::cout << "Block size: " << bmap.blockSize << " bytes" << std::endl;
std::cout << "Mapped blocks: " << bmap.blocksMapped << " out of " << bmap.blocksTotal
<< " (" << std::fixed << std::setprecision(1)
<< (100.0 * static_cast<float>(bmap.blocksMapped) / static_cast<float>(bmap.blocksTotal))
<< "%)" << std::endl;

ret = BmapWriteImage(image_fd, bmap, device, noVerify);
if (ret != 0) {
std::cerr << "Failed to write image to device: " << device << std::endl;
Expand Down