fastboot: add casefold/projid/compress options

fastboot -w --fs-options=casefold
fastboot -w --fs-options=casefold,projid
fastboot format:f2fs --fs-options=casefold
fastboot format:f2fs --fs-options=casefold,projid
fastboot format:f2fs --fs-options=casefold,projid,compress

Bug: 172514669
Bug: 160198145
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
Change-Id: If3fad004fdd25dd754432ce98934b4ae6c8a8706
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4bf791e..62f6ac7 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -454,6 +454,8 @@
             " --skip-reboot              Don't reboot device after flashing.\n"
             " --disable-verity           Sets disable-verity when flashing vbmeta.\n"
             " --disable-verification     Sets disable-verification when flashing vbmeta.\n"
+            " --fs-options=OPTION[,OPTION]\n"
+            "                            Enable filesystem features. OPTION supports casefold, projid, compress\n"
 #if !defined(_WIN32)
             " --wipe-and-use-fbe         Enable file-based encryption, wiping userdata.\n"
 #endif
@@ -1581,7 +1583,7 @@
 static void fb_perform_format(
                               const std::string& partition, int skip_if_not_supported,
                               const std::string& type_override, const std::string& size_override,
-                              const std::string& initial_dir) {
+                              const std::string& initial_dir, const unsigned fs_options) {
     std::string partition_type, partition_size;
 
     struct fastboot_buffer buf;
@@ -1644,7 +1646,7 @@
     logicalBlkSize = fb_get_flash_block_size("logical-block-size");
 
     if (fs_generator_generate(gen, output.path, size, initial_dir,
-            eraseBlkSize, logicalBlkSize)) {
+            eraseBlkSize, logicalBlkSize, fs_options)) {
         die("Cannot generate image for %s", partition.c_str());
     }
 
@@ -1778,6 +1780,7 @@
     bool skip_secondary = false;
     bool set_fbe_marker = false;
     bool force_flash = false;
+    unsigned fs_options = 0;
     int longindex;
     std::string slot_override;
     std::string next_active;
@@ -1795,6 +1798,7 @@
         {"disable-verification", no_argument, 0, 0},
         {"disable-verity", no_argument, 0, 0},
         {"force", no_argument, 0, 0},
+        {"fs-options", required_argument, 0, 0},
         {"header-version", required_argument, 0, 0},
         {"help", no_argument, 0, 'h'},
         {"kernel-offset", required_argument, 0, 0},
@@ -1834,6 +1838,8 @@
                 g_disable_verity = true;
             } else if (name == "force") {
                 force_flash = true;
+            } else if (name == "fs-options") {
+                fs_options = ParseFsOption(optarg);
             } else if (name == "header-version") {
                 g_boot_img_hdr.header_version = strtoul(optarg, nullptr, 0);
             } else if (name == "dtb") {
@@ -1990,7 +1996,7 @@
             std::string partition = next_arg(&args);
 
             auto format = [&](const std::string& partition) {
-                fb_perform_format(partition, 0, type_override, size_override, "");
+                fb_perform_format(partition, 0, type_override, size_override, "", fs_options);
             };
             do_for_partitions(partition, slot_override, format, true);
         } else if (command == "signature") {
@@ -2180,10 +2186,10 @@
             if (partition == "userdata" && set_fbe_marker) {
                 fprintf(stderr, "setting FBE marker on initial userdata...\n");
                 std::string initial_userdata_dir = create_fbemarker_tmpdir();
-                fb_perform_format(partition, 1, partition_type, "", initial_userdata_dir);
+                fb_perform_format(partition, 1, partition_type, "", initial_userdata_dir, fs_options);
                 delete_fbemarker_tmpdir(initial_userdata_dir);
             } else {
-                fb_perform_format(partition, 1, partition_type, "", "");
+                fb_perform_format(partition, 1, partition_type, "", "", fs_options);
             }
         }
     }
@@ -2233,3 +2239,23 @@
     }
     hdr->SetOsVersion(major, minor, patch);
 }
+
+unsigned FastBootTool::ParseFsOption(const char* arg) {
+    unsigned fsOptions = 0;
+
+    std::vector<std::string> options = android::base::Split(arg, ",");
+    if (options.size() < 1)
+        syntax_error("bad options: %s", arg);
+
+    for (size_t i = 0; i < options.size(); ++i) {
+        if (options[i] == "casefold")
+            fsOptions |= (1 << FS_OPT_CASEFOLD);
+        else if (options[i] == "projid")
+            fsOptions |= (1 << FS_OPT_PROJID);
+        else if (options[i] == "compress")
+            fsOptions |= (1 << FS_OPT_COMPRESS);
+        else
+            syntax_error("unsupported options: %s", options[i].c_str());
+    }
+    return fsOptions;
+}