summaryrefslogtreecommitdiff
path: root/partition_tools
diff options
context:
space:
mode:
authorDavid Anderson <dvander@google.com>2023-04-17 21:00:11 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-04-17 21:00:11 +0000
commitd9481184fff48d7cc8d70efb5e1bcbc4f849572e (patch)
treee8c8042aad41077d50f095b86d293d84017b6257 /partition_tools
parent20f400b7768ae8a337085d9b8804478b3d120f97 (diff)
parent9cd252e12253de01209c6a7e2ac8458b0a678ffb (diff)
downloadextras-d9481184fff48d7cc8d70efb5e1bcbc4f849572e.tar.gz
Merge "partition_tools: extend lpunpack for split partitions"
Diffstat (limited to 'partition_tools')
-rw-r--r--partition_tools/lpunpack.cc114
1 files changed, 69 insertions, 45 deletions
diff --git a/partition_tools/lpunpack.cc b/partition_tools/lpunpack.cc
index 1f870c5d..b215c58e 100644
--- a/partition_tools/lpunpack.cc
+++ b/partition_tools/lpunpack.cc
@@ -34,11 +34,12 @@
using namespace android::fs_mgr;
using android::base::unique_fd;
+using android::base::borrowed_fd;
using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
class ImageExtractor final {
public:
- ImageExtractor(unique_fd&& image_fd, std::unique_ptr<LpMetadata>&& metadata,
+ ImageExtractor(std::vector<unique_fd>&& image_fds, std::unique_ptr<LpMetadata>&& metadata,
std::unordered_set<std::string>&& partitions, const std::string& output_dir);
bool Extract();
@@ -48,7 +49,7 @@ class ImageExtractor final {
bool ExtractPartition(const LpMetadataPartition* partition);
bool ExtractExtent(const LpMetadataExtent& extent, int output_fd);
- unique_fd image_fd_;
+ std::vector<unique_fd> image_fds_;
std::unique_ptr<LpMetadata> metadata_;
std::unordered_set<std::string> partitions_;
std::string output_dir_;
@@ -59,16 +60,15 @@ class ImageExtractor final {
// file format.
class SparseWriter final {
public:
- SparseWriter(int output_fd, int image_fd, uint32_t block_size);
+ SparseWriter(borrowed_fd output_fd, uint32_t block_size);
- bool WriteExtent(const LpMetadataExtent& extent);
+ bool WriteExtent(borrowed_fd image_fd, const LpMetadataExtent& extent);
bool Finish();
private:
bool WriteBlock(const uint8_t* data);
- int output_fd_;
- int image_fd_;
+ borrowed_fd output_fd_;
uint32_t block_size_;
off_t hole_size_ = 0;
};
@@ -81,7 +81,14 @@ static int usage(int /* argc */, char* argv[]) {
"Usage:\n"
" %s [options...] SUPER_IMAGE [OUTPUT_DIR]\n"
"\n"
+ "The SUPER_IMAGE argument is mandatory and expected to contain\n"
+ "the metadata. Additional super images are referenced with '-i' as needed to extract\n"
+ "the desired partition[s].\n"
+ "Default OUTPUT_DIR is '.'.\n"
+ "\n"
"Options:\n"
+ " -i, --image=IMAGE Use the given file as an additional super image.\n"
+ " This can be specified multiple times.\n"
" -p, --partition=NAME Extract the named partition. This can\n"
" be specified multiple times.\n"
" -S, --slot=NUM Slot number (default is 0).\n",
@@ -92,6 +99,7 @@ static int usage(int /* argc */, char* argv[]) {
int main(int argc, char* argv[]) {
// clang-format off
struct option options[] = {
+ { "image", required_argument, nullptr, 'i' },
{ "partition", required_argument, nullptr, 'p' },
{ "slot", required_argument, nullptr, 'S' },
{ nullptr, 0, nullptr, 0 },
@@ -100,6 +108,7 @@ int main(int argc, char* argv[]) {
uint32_t slot_num = 0;
std::unordered_set<std::string> partitions;
+ std::vector<std::string> image_files;
int rv, index;
while ((rv = getopt_long_only(argc, argv, "+p:sh", options, &index)) != -1) {
@@ -116,6 +125,9 @@ int main(int argc, char* argv[]) {
return usage(argc, argv);
}
break;
+ case 'i':
+ image_files.push_back(optarg);
+ break;
case 'p':
partitions.emplace(optarg);
break;
@@ -126,56 +138,66 @@ int main(int argc, char* argv[]) {
std::cerr << "Missing super image argument.\n";
return usage(argc, argv);
}
- std::string super_path = argv[optind++];
+ image_files.emplace(image_files.begin(), argv[optind++]);
std::string output_dir = ".";
if (optind + 1 <= argc) {
output_dir = argv[optind++];
}
- if (optind < argc) {
- std::cerr << "Unrecognized command-line arguments.\n";
- return usage(argc, argv);
- }
+ std::unique_ptr<LpMetadata> metadata;
+ std::vector<unique_fd> fds;
- // Done reading arguments; open super.img. PartitionOpener will decorate
- // relative paths with /dev/block/by-name, so get an absolute path here.
- std::string abs_super_path;
- if (!android::base::Realpath(super_path, &abs_super_path)) {
- std::cerr << "realpath failed: " << super_path << ": " << strerror(errno) << "\n";
- return EX_OSERR;
- }
+ for (std::size_t index = 0; index < image_files.size(); ++index) {
+ std::string super_path = image_files[index];
- unique_fd fd(open(super_path.c_str(), O_RDONLY | O_CLOEXEC));
- if (fd < 0) {
- std::cerr << "open failed: " << abs_super_path << ": " << strerror(errno) << "\n";
- return EX_OSERR;
- }
+ // Done reading arguments; open super.img. PartitionOpener will decorate
+ // relative paths with /dev/block/by-name, so get an absolute path here.
+ std::string abs_super_path;
+ if (!android::base::Realpath(super_path, &abs_super_path)) {
+ std::cerr << "realpath failed: " << super_path << ": " << strerror(errno) << "\n";
+ return EX_OSERR;
+ }
+
+ unique_fd fd(open(super_path.c_str(), O_RDONLY | O_CLOEXEC));
+ if (fd < 0) {
+ std::cerr << "open failed: " << abs_super_path << ": " << strerror(errno) << "\n";
+ return EX_OSERR;
+ }
- auto metadata = ReadMetadata(abs_super_path, slot_num);
- if (!metadata) {
SparsePtr ptr(sparse_file_import(fd, false, false), sparse_file_destroy);
if (ptr) {
- std::cerr << "This image appears to be a sparse image. It must be "
- "unsparsed to be"
- << " unpacked.\n";
+ std::cerr << "The image file '"
+ << super_path
+ << "' appears to be a sparse image. It must be unsparsed to be unpacked.\n";
return EX_USAGE;
}
- std::cerr << "Image does not appear to be in super-partition format.\n";
- return EX_USAGE;
+
+ if (!metadata) {
+ metadata = ReadMetadata(abs_super_path, slot_num);
+ if (!metadata) {
+ std::cerr << "Could not read metadata from the super image file '"
+ << super_path
+ << "'.\n";
+ return EX_USAGE;
+ }
+ }
+
+ fds.emplace_back(std::move(fd));
}
- ImageExtractor extractor(std::move(fd), std::move(metadata), std::move(partitions), output_dir);
+ // Now do actual extraction.
+ ImageExtractor extractor(std::move(fds), std::move(metadata), std::move(partitions), output_dir);
if (!extractor.Extract()) {
return EX_SOFTWARE;
}
return EX_OK;
}
-ImageExtractor::ImageExtractor(unique_fd&& image_fd, std::unique_ptr<LpMetadata>&& metadata,
+ImageExtractor::ImageExtractor(std::vector<unique_fd>&& image_fds, std::unique_ptr<LpMetadata>&& metadata,
std::unordered_set<std::string>&& partitions,
const std::string& output_dir)
- : image_fd_(std::move(image_fd)),
+ : image_fds_(std::move(image_fds)),
metadata_(std::move(metadata)),
partitions_(std::move(partitions)),
output_dir_(output_dir) {}
@@ -186,6 +208,7 @@ bool ImageExtractor::Extract() {
}
for (const auto& [name, info] : partition_map_) {
+ std::cout << "Attempting to extract partition '" << name << "'...\n";
if (!ExtractPartition(info)) {
return false;
}
@@ -217,13 +240,14 @@ bool ImageExtractor::ExtractPartition(const LpMetadataPartition* partition) {
for (uint32_t i = 0; i < partition->num_extents; i++) {
uint32_t index = partition->first_extent_index + i;
const LpMetadataExtent& extent = metadata_->extents[index];
+ std::cout << " Dealing with extent " << i << " from target source " << extent.target_source << "...\n";
if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
std::cerr << "Unsupported target type in extent: " << extent.target_type << "\n";
return false;
}
- if (extent.target_source != 0) {
- std::cerr << "Split super devices are not supported.\n";
+ if (extent.target_source >= image_fds_.size()) {
+ std::cerr << "Insufficient number of super images passed, need at least " << extent.target_source + 1 << ".\n";
return false;
}
total_size += extent.num_sectors * LP_SECTOR_SIZE;
@@ -237,28 +261,28 @@ bool ImageExtractor::ExtractPartition(const LpMetadataPartition* partition) {
return false;
}
- SparseWriter writer(output_fd, image_fd_, metadata_->geometry.logical_block_size);
+ SparseWriter writer(output_fd, metadata_->geometry.logical_block_size);
// Extract each extent into output_fd.
for (uint32_t i = 0; i < partition->num_extents; i++) {
uint32_t index = partition->first_extent_index + i;
const LpMetadataExtent& extent = metadata_->extents[index];
- if (!writer.WriteExtent(extent)) {
+ if (!writer.WriteExtent(image_fds_[extent.target_source], extent)) {
return false;
}
}
return writer.Finish();
}
-SparseWriter::SparseWriter(int output_fd, int image_fd, uint32_t block_size)
- : output_fd_(output_fd), image_fd_(image_fd), block_size_(block_size) {}
+SparseWriter::SparseWriter(borrowed_fd output_fd, uint32_t block_size)
+ : output_fd_(output_fd), block_size_(block_size) {}
-bool SparseWriter::WriteExtent(const LpMetadataExtent& extent) {
+bool SparseWriter::WriteExtent(borrowed_fd image_fd, const LpMetadataExtent& extent) {
auto buffer = std::make_unique<uint8_t[]>(block_size_);
off_t super_offset = extent.target_data * LP_SECTOR_SIZE;
- if (lseek(image_fd_, super_offset, SEEK_SET) < 0) {
+ if (lseek(image_fd.get(), super_offset, SEEK_SET) < 0) {
std::cerr << "image lseek failed: " << strerror(errno) << "\n";
return false;
}
@@ -269,7 +293,7 @@ bool SparseWriter::WriteExtent(const LpMetadataExtent& extent) {
std::cerr << "extent is not block-aligned\n";
return false;
}
- if (!android::base::ReadFully(image_fd_, buffer.get(), block_size_)) {
+ if (!android::base::ReadFully(image_fd, buffer.get(), block_size_)) {
std::cerr << "read failed: " << strerror(errno) << "\n";
return false;
}
@@ -297,7 +321,7 @@ bool SparseWriter::WriteBlock(const uint8_t* data) {
}
if (hole_size_) {
- if (lseek(output_fd_, hole_size_, SEEK_CUR) < 0) {
+ if (lseek(output_fd_.get(), hole_size_, SEEK_CUR) < 0) {
std::cerr << "lseek failed: " << strerror(errno) << "\n";
return false;
}
@@ -312,12 +336,12 @@ bool SparseWriter::WriteBlock(const uint8_t* data) {
bool SparseWriter::Finish() {
if (hole_size_) {
- off_t offset = lseek(output_fd_, 0, SEEK_CUR);
+ off_t offset = lseek(output_fd_.get(), 0, SEEK_CUR);
if (offset < 0) {
std::cerr << "lseek failed: " << strerror(errno) << "\n";
return false;
}
- if (ftruncate(output_fd_, offset + hole_size_) < 0) {
+ if (ftruncate(output_fd_.get(), offset + hole_size_) < 0) {
std::cerr << "ftruncate failed: " << strerror(errno) << "\n";
return false;
}