From 922cfefbb9b1e7a2d32331c10a15c497ae7acd89 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Sep 2019 18:56:43 -0700 Subject: [PATCH] liblp: Add a helper to differentiate empty from non-empty images. Also, finally explain the difference between these somewhere. Bug: 140204341 Test: lpdump Change-Id: I128780b01a28e893afac65f3aa4f4a8d36032d63 --- fs_mgr/liblp/images.cpp | 34 ++++++++++++++++++++++++++++++ fs_mgr/liblp/include/liblp/liblp.h | 9 +++++++- fs_mgr/liblp/utility.cpp | 6 +++--- fs_mgr/liblp/utility.h | 5 ++++- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp index 58a88b58e..6b842b3cb 100644 --- a/fs_mgr/liblp/images.cpp +++ b/fs_mgr/liblp/images.cpp @@ -17,6 +17,7 @@ #include "images.h" #include +#include #include @@ -27,12 +28,45 @@ namespace android { namespace fs_mgr { +using android::base::borrowed_fd; using android::base::unique_fd; #if defined(_WIN32) static const int O_NOFOLLOW = 0; #endif +static bool IsEmptySuperImage(borrowed_fd fd) { + struct stat s; + if (fstat(fd.get(), &s) < 0) { + PERROR << __PRETTY_FUNCTION__ << " fstat failed"; + return false; + } + if (s.st_size < LP_METADATA_GEOMETRY_SIZE) { + return false; + } + + // Rewind back to the start, read the geometry struct. + LpMetadataGeometry geometry = {}; + if (SeekFile64(fd.get(), 0, SEEK_SET) < 0) { + PERROR << __PRETTY_FUNCTION__ << " lseek failed"; + return false; + } + if (!android::base::ReadFully(fd, &geometry, sizeof(geometry))) { + PERROR << __PRETTY_FUNCTION__ << " read failed"; + return false; + } + return geometry.magic == LP_METADATA_GEOMETRY_MAGIC; +} + +bool IsEmptySuperImage(const std::string& file) { + unique_fd fd = GetControlFileOrOpen(file, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + PERROR << __PRETTY_FUNCTION__ << " open failed"; + return false; + } + return IsEmptySuperImage(fd); +} + std::unique_ptr ReadFromImageFile(int fd) { std::unique_ptr buffer = std::make_unique(LP_METADATA_GEOMETRY_SIZE); if (SeekFile64(fd, 0, SEEK_SET) < 0) { diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h index 135a1b3a6..cd860cd1f 100644 --- a/fs_mgr/liblp/include/liblp/liblp.h +++ b/fs_mgr/liblp/include/liblp/liblp.h @@ -70,8 +70,15 @@ bool UpdatePartitionTable(const std::string& super_partition, const LpMetadata& uint32_t slot_number); std::unique_ptr ReadMetadata(const std::string& super_partition, uint32_t slot_number); +// Returns whether an image is an "empty" image or not. An empty image contains +// only metadata. Unlike a flashed block device, there are no reserved bytes or +// backup sections, and only one slot is stored (even if multiple slots are +// supported). It is a format specifically for storing only metadata. +bool IsEmptySuperImage(const std::string& file); + // Read/Write logical partition metadata to an image file, for diagnostics or -// flashing. +// flashing. If no partition images are specified, the file will be in the +// empty format. bool WriteToImageFile(const std::string& file, const LpMetadata& metadata, uint32_t block_size, const std::map& images, bool sparsify); bool WriteToImageFile(const std::string& file, const LpMetadata& metadata); diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp index afcce8f0a..48c5c8318 100644 --- a/fs_mgr/liblp/utility.cpp +++ b/fs_mgr/liblp/utility.cpp @@ -205,9 +205,9 @@ bool SetBlockReadonly(int fd, bool readonly) { #endif } -base::unique_fd GetControlFileOrOpen(const char* path, int flags) { +base::unique_fd GetControlFileOrOpen(std::string_view path, int flags) { #if defined(__ANDROID__) - int fd = android_get_control_file(path); + int fd = android_get_control_file(path.data()); if (fd >= 0) { int newfd = TEMP_FAILURE_RETRY(dup(fd)); if (newfd >= 0) { @@ -216,7 +216,7 @@ base::unique_fd GetControlFileOrOpen(const char* path, int flags) { PERROR << "Cannot dup fd for already controlled file: " << path << ", reopening..."; } #endif - return base::unique_fd(open(path, flags)); + return base::unique_fd(open(path.data(), flags)); } bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number, diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h index 25ab66bae..06617696c 100644 --- a/fs_mgr/liblp/utility.h +++ b/fs_mgr/liblp/utility.h @@ -21,6 +21,9 @@ #include #include +#include +#include + #include #include @@ -94,7 +97,7 @@ bool UpdatePartitionName(LpMetadataPartition* partition, const std::string& name // Call BLKROSET ioctl on fd so that fd is readonly / read-writable. bool SetBlockReadonly(int fd, bool readonly); -::android::base::unique_fd GetControlFileOrOpen(const char* path, int flags); +::android::base::unique_fd GetControlFileOrOpen(std::string_view path, int flags); // For Virtual A/B updates, modify |metadata| so that it can be written to |target_slot_number|. bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number,