liblp: Add ReadImageFromBlob.
This change enables reading metadata images from memory, for situations where using file descriptors is not practical (such as fastbootd flash). Bug: 78793464 Test: liblp_test gtest Change-Id: I9ad08b0ddd4cbb96e87583237a90785e0f4befa4
This commit is contained in:
parent
1eb3ea37dc
commit
ee4075d84d
|
@ -41,6 +41,23 @@ std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
|
|||
return ParseMetadata(geometry, fd);
|
||||
}
|
||||
|
||||
std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes) {
|
||||
if (bytes < LP_METADATA_GEOMETRY_SIZE) {
|
||||
LERROR << __PRETTY_FUNCTION__ << ": " << bytes << " is smaller than geometry header";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LpMetadataGeometry geometry;
|
||||
if (!ParseGeometry(data, &geometry)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t* metadata_buffer =
|
||||
reinterpret_cast<const uint8_t*>(data) + LP_METADATA_GEOMETRY_SIZE;
|
||||
size_t metadata_buffer_size = bytes - LP_METADATA_GEOMETRY_SIZE;
|
||||
return ParseMetadata(geometry, metadata_buffer, metadata_buffer_size);
|
||||
}
|
||||
|
||||
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
|
||||
android::base::unique_fd fd(open(file, O_RDONLY));
|
||||
if (fd < 0) {
|
||||
|
|
|
@ -63,6 +63,7 @@ bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t bl
|
|||
const std::map<std::string, std::string>& images);
|
||||
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
|
||||
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
|
||||
std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
|
||||
|
||||
// Helper to extract safe C++ strings from partition info.
|
||||
std::string GetPartitionName(const LpMetadataPartition& partition);
|
||||
|
|
|
@ -394,6 +394,27 @@ TEST(liblp, ImageFiles) {
|
|||
ASSERT_NE(imported, nullptr);
|
||||
}
|
||||
|
||||
// Test that we can read images from buffers.
|
||||
TEST(liblp, ImageFilesInMemory) {
|
||||
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
|
||||
ASSERT_NE(builder, nullptr);
|
||||
ASSERT_TRUE(AddDefaultPartitions(builder.get()));
|
||||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
|
||||
unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
|
||||
ASSERT_GE(fd, 0);
|
||||
ASSERT_TRUE(WriteToImageFile(fd, *exported.get()));
|
||||
|
||||
int64_t offset = SeekFile64(fd, 0, SEEK_CUR);
|
||||
ASSERT_GE(offset, 0);
|
||||
ASSERT_EQ(SeekFile64(fd, 0, SEEK_SET), 0);
|
||||
|
||||
size_t bytes = static_cast<size_t>(offset);
|
||||
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(bytes);
|
||||
ASSERT_TRUE(android::base::ReadFully(fd, buffer.get(), bytes));
|
||||
ASSERT_NE(ReadFromImageBlob(buffer.get(), bytes), nullptr);
|
||||
}
|
||||
|
||||
class BadWriter {
|
||||
public:
|
||||
// When requested, write garbage instead of the requested bytes, then
|
||||
|
|
|
@ -48,9 +48,27 @@ class FileReader final : public Reader {
|
|||
int fd_;
|
||||
};
|
||||
|
||||
// Parse an LpMetadataGeometry from a buffer. The buffer must be at least
|
||||
// LP_METADATA_GEOMETRY_SIZE bytes in size.
|
||||
static bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
|
||||
class MemoryReader final : public Reader {
|
||||
public:
|
||||
MemoryReader(const void* buffer, size_t size)
|
||||
: buffer_(reinterpret_cast<const uint8_t*>(buffer)), size_(size), pos_(0) {}
|
||||
bool ReadFully(void* out, size_t length) override {
|
||||
if (size_ - pos_ < length) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
memcpy(out, buffer_ + pos_, length);
|
||||
pos_ += length;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t* buffer_;
|
||||
size_t size_;
|
||||
size_t pos_;
|
||||
};
|
||||
|
||||
bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
|
||||
static_assert(sizeof(*geometry) <= LP_METADATA_GEOMETRY_SIZE);
|
||||
memcpy(geometry, buffer, sizeof(*geometry));
|
||||
|
||||
|
@ -254,6 +272,12 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
|
|||
return metadata;
|
||||
}
|
||||
|
||||
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
|
||||
size_t size) {
|
||||
MemoryReader reader(buffer, size);
|
||||
return ParseMetadata(geometry, &reader);
|
||||
}
|
||||
|
||||
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, int fd) {
|
||||
FileReader reader(fd);
|
||||
return ParseMetadata(geometry, &reader);
|
||||
|
|
|
@ -26,11 +26,16 @@
|
|||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
|
||||
// Parse an LpMetadataGeometry from a buffer. The buffer must be at least
|
||||
// LP_METADATA_GEOMETRY_SIZE bytes in size.
|
||||
bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry);
|
||||
|
||||
// Helper functions for manually reading geometry and metadata.
|
||||
bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
|
||||
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, int fd);
|
||||
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
|
||||
size_t size);
|
||||
bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
|
||||
|
||||
// These functions assume a valid geometry and slot number.
|
||||
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
|
||||
|
|
Loading…
Reference in New Issue