libsnapshot: Don't try to truncate block devices

When we're writing to a block device, we can't truncate. Ignore those
commands. Truncate mostly just saves time in the read phase by chopping
off unused data in the event finalize wasn't called.

Bug: 172026020
Test: cow_api_test
Change-Id: I3befc71fa9597edf8243d0f9e17440db91409aea
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index dcf259c..b41d92b 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -122,6 +122,13 @@
         is_dev_null_ = true;
     } else {
         fd_ = fd;
+
+        struct stat stat;
+        if (fstat(fd.get(), &stat) < 0) {
+            PLOG(ERROR) << "fstat failed";
+            return false;
+        }
+        is_block_device_ = S_ISBLK(stat.st_mode);
     }
     return true;
 }
@@ -217,12 +224,11 @@
     // Free reader so we own the descriptor position again.
     reader = nullptr;
 
-    // Position for new writing
-    if (ftruncate(fd_.get(), next_op_pos_) != 0) {
-        PLOG(ERROR) << "Failed to trim file";
+    // Remove excess data
+    if (!Truncate(next_op_pos_)) {
         return false;
     }
-    if (lseek(fd_.get(), 0, SEEK_END) < 0) {
+    if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
         PLOG(ERROR) << "lseek failed";
         return false;
     }
@@ -445,5 +451,16 @@
     return Sync();
 }
 
+bool CowWriter::Truncate(off_t length) {
+    if (is_dev_null_ || is_block_device_) {
+        return true;
+    }
+    if (ftruncate(fd_.get(), length) < 0) {
+        PLOG(ERROR) << "Failed to truncate.";
+        return false;
+    }
+    return true;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index d0a861b..e9320b0 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -123,6 +123,7 @@
 
     bool SetFd(android::base::borrowed_fd fd);
     bool Sync();
+    bool Truncate(off_t length);
 
   private:
     android::base::unique_fd owned_fd_;
@@ -133,6 +134,7 @@
     uint64_t next_op_pos_ = 0;
     bool is_dev_null_ = false;
     bool merge_in_progress_ = false;
+    bool is_block_device_ = false;
 
     // :TODO: this is not efficient, but stringstream ubsan aborts because some
     // bytes overflow a signed char.