Merge "Fastboot: use flash erase & logical block size for building userdata"
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e7f1a07..a4a0b52 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1303,6 +1303,36 @@
     return num;
 }
 
+static std::string fb_fix_numeric_var(std::string var) {
+    // Some bootloaders (angler, for example), send spurious leading whitespace.
+    var = android::base::Trim(var);
+    // Some bootloaders (hammerhead, for example) use implicit hex.
+    // This code used to use strtol with base 16.
+    if (!android::base::StartsWith(var, "0x")) var = "0x" + var;
+    return var;
+}
+
+static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
+    std::string sizeString;
+    if (!fb_getvar(transport, name.c_str(), &sizeString)) {
+        /* This device does not report flash block sizes, so return 0 */
+        return 0;
+    }
+    sizeString = fb_fix_numeric_var(sizeString);
+
+    unsigned size;
+    if (!android::base::ParseUint(sizeString, &size)) {
+        fprintf(stderr, "Couldn't parse %s '%s'.\n", name.c_str(), sizeString.c_str());
+        return 0;
+    }
+    if (size < 4096 || (size & (size - 1)) != 0) {
+        fprintf(stderr, "Invalid %s %u: must be a power of 2 and at least 4096.\n",
+                name.c_str(), size);
+        return 0;
+    }
+    return size;
+}
+
 static void fb_perform_format(Transport* transport,
                               const char* partition, int skip_if_not_supported,
                               const char* type_override, const char* size_override,
@@ -1345,11 +1375,7 @@
         }
         partition_size = size_override;
     }
-    // Some bootloaders (angler, for example), send spurious leading whitespace.
-    partition_size = android::base::Trim(partition_size);
-    // Some bootloaders (hammerhead, for example) use implicit hex.
-    // This code used to use strtol with base 16.
-    if (!android::base::StartsWith(partition_size, "0x")) partition_size = "0x" + partition_size;
+    partition_size = fb_fix_numeric_var(partition_size);
 
     gen = fs_get_generator(partition_type);
     if (!gen) {
@@ -1370,7 +1396,12 @@
     }
 
     fd = fileno(tmpfile());
-    if (fs_generator_generate(gen, fd, size, initial_dir)) {
+
+    unsigned eraseBlkSize, logicalBlkSize;
+    eraseBlkSize = fb_get_flash_block_size(transport, "erase-block-size");
+    logicalBlkSize = fb_get_flash_block_size(transport, "logical-block-size");
+
+    if (fs_generator_generate(gen, fd, size, initial_dir, eraseBlkSize, logicalBlkSize)) {
         fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
         close(fd);
         return;
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 9b73165..5d9ccfe 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -14,18 +14,21 @@
 #include <ext4_utils/make_ext4fs.h>
 #include <sparse/sparse.h>
 
-static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
+static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir,
+                                       unsigned eraseBlkSize, unsigned logicalBlkSize)
 {
     if (initial_dir.empty()) {
-        make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+        make_ext4fs_sparse_fd_align(fd, partSize, NULL, NULL, eraseBlkSize, logicalBlkSize);
     } else {
-        make_ext4fs_sparse_fd_directory(fd, partSize, NULL, NULL, initial_dir.c_str());
+        make_ext4fs_sparse_fd_directory_align(fd, partSize, NULL, NULL, initial_dir.c_str(),
+                                              eraseBlkSize, logicalBlkSize);
     }
     return 0;
 }
 
 #ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir)
+static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir,
+                               unsigned /* unused */, unsigned /* unused */)
 {
     if (!initial_dir.empty()) {
         fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
@@ -39,7 +42,8 @@
     const char* fs_type;  //must match what fastboot reports for partition type
 
     //returns 0 or error value
-    int (*generate)(int fd, long long partSize, const std::string& initial_dir);
+    int (*generate)(int fd, long long partSize, const std::string& initial_dir,
+                    unsigned eraseBlkSize, unsigned logicalBlkSize);
 
 } generators[] = {
     { "ext4", generate_ext4_image},
@@ -58,7 +62,7 @@
 }
 
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
-    const std::string& initial_dir)
+    const std::string& initial_dir, unsigned eraseBlkSize, unsigned logicalBlkSize)
 {
-    return gen->generate(tmpFileNo, partSize, initial_dir);
+    return gen->generate(tmpFileNo, partSize, initial_dir, eraseBlkSize, logicalBlkSize);
 }
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 0a68507..0a5f5a4 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -8,6 +8,6 @@
 
 const struct fs_generator* fs_get_generator(const std::string& fs_type);
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
-    const std::string& initial_dir);
+    const std::string& initial_dir, unsigned eraseBlkSize = 0, unsigned logicalBlkSize = 0);
 
 #endif