Merge changes I9ad08b0d,I7fb1ef4f,I5b24b9d9
* changes:
liblp: Add ReadImageFromBlob.
liblp: Refactor ParseMetadata to read from non-descriptors.
liblp: Always copy geometry to LpMetadata.
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index a361a5d..742b1d0 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -38,12 +38,24 @@
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
return nullptr;
}
- std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
- if (!metadata) {
+ 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;
}
- metadata->geometry = geometry;
- return metadata;
+
+ 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) {
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index dd9a9cd..6da24f6 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -63,6 +63,7 @@
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);
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index a8d6d70..329a901 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -394,6 +394,27 @@
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
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 117da59..117f5d5 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -30,9 +30,45 @@
namespace android {
namespace fs_mgr {
-// 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) {
+// Helper class for reading descriptors and memory buffers in the same manner.
+class Reader {
+ public:
+ virtual ~Reader(){};
+ virtual bool ReadFully(void* buffer, size_t length) = 0;
+};
+
+class FileReader final : public Reader {
+ public:
+ explicit FileReader(int fd) : fd_(fd) {}
+ bool ReadFully(void* buffer, size_t length) override {
+ return android::base::ReadFully(fd_, buffer, length);
+ }
+
+ private:
+ int fd_;
+};
+
+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));
@@ -171,16 +207,18 @@
// Parse and validate all metadata at the current position in the given file
// descriptor.
-std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
+static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry,
+ Reader* reader) {
// First read and validate the header.
std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
- if (!android::base::ReadFully(fd, &metadata->header, sizeof(metadata->header))) {
+ if (!reader->ReadFully(&metadata->header, sizeof(metadata->header))) {
PERROR << __PRETTY_FUNCTION__ << "read " << sizeof(metadata->header) << "bytes failed";
return nullptr;
}
if (!ValidateMetadataHeader(metadata->header)) {
return nullptr;
}
+ metadata->geometry = geometry;
LpMetadataHeader& header = metadata->header;
@@ -191,7 +229,7 @@
LERROR << "Out of memory reading logical partition tables.";
return nullptr;
}
- if (!android::base::ReadFully(fd, buffer.get(), header.tables_size)) {
+ if (!reader->ReadFully(buffer.get(), header.tables_size)) {
PERROR << __PRETTY_FUNCTION__ << "read " << header.tables_size << "bytes failed";
return nullptr;
}
@@ -231,10 +269,20 @@
metadata->extents.push_back(extent);
}
-
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);
+}
+
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
uint32_t slot_number) {
int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
@@ -242,7 +290,7 @@
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
}
- return ParseMetadata(fd);
+ return ParseMetadata(geometry, fd);
}
std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
@@ -252,7 +300,7 @@
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
}
- return ParseMetadata(fd);
+ return ParseMetadata(geometry, fd);
}
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
@@ -268,13 +316,10 @@
// Read the priamry copy, and if that fails, try the backup.
std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
- if (!metadata) {
- metadata = ReadBackupMetadata(fd, geometry, slot_number);
- }
if (metadata) {
- metadata->geometry = geometry;
+ return metadata;
}
- return metadata;
+ return ReadBackupMetadata(fd, geometry, slot_number);
}
std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index 843b2f2..9f6ca6e 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -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.
+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);
-std::unique_ptr<LpMetadata> ParseMetadata(int fd);
// These functions assume a valid geometry and slot number.
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,