Merge "libfiemap_writer: Improve device unwrapping to support simple linear devices."
am: 87db478ad6

Change-Id: I7b248ead7f8b9297d32c6413aab0ef235406a683
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 788039d..d54b6ef 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -388,5 +388,13 @@
     }
 }
 
+std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) {
+    if (const void* p = memchr(spec.target_type, '\0', sizeof(spec.target_type))) {
+        ptrdiff_t length = reinterpret_cast<const char*>(p) - spec.target_type;
+        return std::string{spec.target_type, static_cast<size_t>(length)};
+    }
+    return std::string{spec.target_type, sizeof(spec.target_type)};
+}
+
 }  // namespace dm
 }  // namespace android
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 6219923..c5881dd 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -179,6 +179,10 @@
     EXPECT_EQ(targets[1].spec.sector_start, 1);
     EXPECT_EQ(targets[1].spec.length, 1);
 
+    // Test GetTargetType().
+    EXPECT_EQ(DeviceMapper::GetTargetType(targets[0].spec), std::string{"linear"});
+    EXPECT_EQ(DeviceMapper::GetTargetType(targets[1].spec), std::string{"linear"});
+
     // Normally the TestDevice destructor would delete this, but at least one
     // test should ensure that device deletion works.
     ASSERT_TRUE(dev.Destroy());
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 3d223e3..afcb090 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -144,6 +144,8 @@
     // mapper device from the kernel.
     bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table);
 
+    static std::string GetTargetType(const struct dm_target_spec& spec);
+
   private:
     // Maximum possible device mapper targets registered in the kernel.
     // This is only used to read the list of targets from kernel so we allocate
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index f064436..0a3ba6c 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -89,6 +89,31 @@
     return true;
 }
 
+static bool ValidateDmTarget(const DeviceMapper::TargetInfo& target) {
+    const auto& entry = target.spec;
+    if (entry.sector_start != 0) {
+        LOG(INFO) << "Stopping at target with non-zero starting sector";
+        return false;
+    }
+
+    auto target_type = DeviceMapper::GetTargetType(entry);
+    if (target_type == "bow" || target_type == "default-key" || target_type == "crypt") {
+        return true;
+    }
+    if (target_type == "linear") {
+        auto pieces = android::base::Split(target.data, " ");
+        if (pieces[1] != "0") {
+            LOG(INFO) << "Stopping at complex linear target with non-zero starting sector: "
+                      << pieces[1];
+            return false;
+        }
+        return true;
+    }
+
+    LOG(INFO) << "Stopping at complex target type " << target_type;
+    return false;
+}
+
 static bool DeviceMapperStackPop(const std::string& bdev, std::string* bdev_raw) {
     *bdev_raw = bdev;
 
@@ -128,15 +153,7 @@
         LOG(INFO) << "Stopping at complex table for " << dm_name << " at " << bdev;
         return true;
     }
-    const auto& entry = table[0].spec;
-    std::string target_type(std::string(entry.target_type, sizeof(entry.target_type)).c_str());
-    if (target_type != "bow" && target_type != "default-key" && target_type != "crypt") {
-        LOG(INFO) << "Stopping at complex target-type " << target_type << " for " << dm_name
-                  << " at " << bdev;
-        return true;
-    }
-    if (entry.sector_start != 0) {
-        LOG(INFO) << "Stopping at target-type with non-zero starting sector";
+    if (!ValidateDmTarget(table[0])) {
         return true;
     }