fs_mgr: store file_contents_mode and file_names_mode directly

It doesn't really make sense to have extra logic to convert these
strings to enums then back again to strings for usage, especially
since with the C++ fstab, these strings are small enough to fall into
the small string optimization of std::string.

This will help make future changes cleaner as well.
Test: boot, fs_mgr_test

Change-Id: I5669ed10f2fc3eafdb137747446a2e93c24d55c4
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 9d4f280..13e2fd0 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <array>
 #include <utility>
 #include <vector>
 
@@ -55,8 +56,8 @@
     int max_comp_streams = 0;
     off64_t zram_size = 0;
     off64_t reserved_size = 0;
-    int file_contents_mode = 0;
-    int file_names_mode = 0;
+    std::string file_contents_mode;
+    std::string file_names_mode;
     off64_t erase_blk_size = 0;
     off64_t logical_blk_size = 0;
     std::string vbmeta_partition;
@@ -129,51 +130,6 @@
         {0, 0},
 };
 
-#define EM_AES_256_XTS  1
-#define EM_ICE          2
-#define EM_AES_256_CTS  3
-#define EM_AES_256_HEH  4
-#define EM_ADIANTUM     5
-
-static const struct flag_list file_contents_encryption_modes[] = {
-    {"aes-256-xts", EM_AES_256_XTS},
-    {"adiantum", EM_ADIANTUM},
-    {"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
-    {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
-    {0, 0},
-};
-
-static const struct flag_list file_names_encryption_modes[] = {
-    {"aes-256-cts", EM_AES_256_CTS},
-    {"aes-256-heh", EM_AES_256_HEH},
-    {"adiantum", EM_ADIANTUM},
-    {0, 0},
-};
-
-static int encryption_mode_to_flag(const struct flag_list* list, const char* mode,
-                                   const char* type) {
-    const struct flag_list *j;
-
-    for (j = list; j->name; ++j) {
-        if (!strcmp(mode, j->name)) {
-            return j->flag;
-        }
-    }
-    LERROR << "Unknown " << type << " encryption mode: " << mode;
-    return 0;
-}
-
-static const char* flag_to_encryption_mode(const struct flag_list* list, uint64_t flag) {
-    const struct flag_list *j;
-
-    for (j = list; j->name; ++j) {
-        if (flag == j->flag) {
-            return j->name;
-        }
-    }
-    return nullptr;
-}
-
 static off64_t calculate_zram_size(unsigned int percentage) {
     off64_t total;
 
@@ -217,6 +173,59 @@
     return false;
 }
 
+const static std::array<const char*, 3> kFileContentsEncryptionMode = {
+        "aes-256-xts",
+        "adiantum",
+        "ice",
+};
+
+const static std::array<const char*, 3> kFileNamesEncryptionMode = {
+        "aes-256-cts",
+        "aes-256-heh",
+        "adiantum",
+};
+
+static void ParseFileEncryption(const std::string& arg, struct fs_mgr_flag_values* flag_vals) {
+    // The fileencryption flag is followed by an = and the mode of contents encryption, then
+    // optionally a and the mode of filenames encryption (defaults to aes-256-cts).  Get it and
+    // return it.
+
+    auto parts = Split(arg, ":");
+    if (parts.empty() || parts.size() > 2) {
+        LWARNING << "Warning: fileencryption= flag malformed: " << arg;
+        return;
+    }
+
+    // Alias for backwards compatibility.
+    if (parts[0] == "software") {
+        parts[0] = "aes-256-xts";
+    }
+
+    if (std::find(kFileContentsEncryptionMode.begin(), kFileContentsEncryptionMode.end(),
+                  parts[0]) == kFileContentsEncryptionMode.end()) {
+        LWARNING << "fileencryption= flag malformed, file contents encryption mode not found: "
+                 << arg;
+        return;
+    }
+
+    flag_vals->file_contents_mode = parts[0];
+
+    if (parts.size() == 2) {
+        if (std::find(kFileNamesEncryptionMode.begin(), kFileNamesEncryptionMode.end(), parts[1]) ==
+            kFileNamesEncryptionMode.end()) {
+            LWARNING << "fileencryption= flag malformed, file names encryption mode not found: "
+                     << arg;
+            return;
+        }
+
+        flag_vals->file_names_mode = parts[1];
+    } else if (flag_vals->file_contents_mode == "adiantum") {
+        flag_vals->file_names_mode = "adiantum";
+    } else {
+        flag_vals->file_names_mode = "aes-256-cts";
+    }
+}
+
 static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_flag_values* flag_vals,
                             std::string* fs_options) {
     uint64_t f = 0;
@@ -260,31 +269,10 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = arg;
-                    flag_vals->file_contents_mode = EM_AES_256_XTS;
-                    flag_vals->file_names_mode = EM_AES_256_CTS;
+                    flag_vals->file_contents_mode = "aes-256-xts";
+                    flag_vals->file_names_mode = "aes-256-cts";
                 } else if (flag == MF_FILEENCRYPTION) {
-                    /* The fileencryption flag is followed by an = and
-                     * the mode of contents encryption, then optionally a
-                     * : and the mode of filenames encryption (defaults
-                     * to aes-256-cts).  Get it and return it.
-                     */
-                    auto mode = arg;
-                    auto colon = strchr(mode, ':');
-                    if (colon) {
-                        *colon = '\0';
-                    }
-                    flag_vals->file_contents_mode =
-                        encryption_mode_to_flag(file_contents_encryption_modes,
-                                                mode, "file contents");
-                    if (colon) {
-                        flag_vals->file_names_mode =
-                            encryption_mode_to_flag(file_names_encryption_modes,
-                                                    colon + 1, "file names");
-                    } else if (flag_vals->file_contents_mode == EM_ADIANTUM) {
-                        flag_vals->file_names_mode = EM_ADIANTUM;
-                    } else {
-                        flag_vals->file_names_mode = EM_AES_256_CTS;
-                    }
+                    ParseFileEncryption(arg, flag_vals);
                 } else if (flag == MF_KEYDIRECTORY) {
                     /* The metadata flag is followed by an = and the
                      * directory for the keys.  Get it and return it.
@@ -582,8 +570,8 @@
         entry.max_comp_streams = flag_vals.max_comp_streams;
         entry.zram_size = flag_vals.zram_size;
         entry.reserved_size = flag_vals.reserved_size;
-        entry.file_contents_mode = flag_vals.file_contents_mode;
-        entry.file_names_mode = flag_vals.file_names_mode;
+        entry.file_contents_mode = std::move(flag_vals.file_contents_mode);
+        entry.file_names_mode = std::move(flag_vals.file_names_mode);
         entry.erase_blk_size = flag_vals.erase_blk_size;
         entry.logical_blk_size = flag_vals.logical_blk_size;
         entry.sysfs_path = std::move(flag_vals.sysfs_path);
@@ -831,6 +819,8 @@
         free(fstab->recs[i].key_loc);
         free(fstab->recs[i].key_dir);
         free(fstab->recs[i].label);
+        free(fstab->recs[i].file_contents_mode);
+        free(fstab->recs[i].file_names_mode);
         free(fstab->recs[i].sysfs_path);
         free(fstab->recs[i].zram_loopback_path);
         free(fstab->recs[i].zram_backing_dev_path);
@@ -972,8 +962,8 @@
         legacy_fstab->recs[i].max_comp_streams = fstab[i].max_comp_streams;
         legacy_fstab->recs[i].zram_size = fstab[i].zram_size;
         legacy_fstab->recs[i].reserved_size = fstab[i].reserved_size;
-        legacy_fstab->recs[i].file_contents_mode = fstab[i].file_contents_mode;
-        legacy_fstab->recs[i].file_names_mode = fstab[i].file_names_mode;
+        legacy_fstab->recs[i].file_contents_mode = strdup(fstab[i].file_contents_mode.c_str());
+        legacy_fstab->recs[i].file_names_mode = strdup(fstab[i].file_names_mode.c_str());
         legacy_fstab->recs[i].erase_blk_size = fstab[i].erase_blk_size;
         legacy_fstab->recs[i].logical_blk_size = fstab[i].logical_blk_size;
         legacy_fstab->recs[i].sysfs_path = strdup(fstab[i].sysfs_path.c_str());
@@ -1019,14 +1009,10 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
-void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
-                                      const char **contents_mode_ret,
-                                      const char **filenames_mode_ret)
-{
-    *contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
-                                                 fstab->file_contents_mode);
-    *filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
-                                                  fstab->file_names_mode);
+void fs_mgr_get_file_encryption_modes(const struct fstab_rec* fstab, const char** contents_mode_ret,
+                                      const char** filenames_mode_ret) {
+    *contents_mode_ret = fstab->file_contents_mode;
+    *filenames_mode_ret = fstab->file_names_mode;
 }
 
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 38f96c0..c550bac 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -54,8 +54,8 @@
     int max_comp_streams;
     off64_t zram_size;
     off64_t reserved_size;
-    int file_contents_mode;
-    int file_names_mode;
+    char* file_contents_mode;
+    char* file_names_mode;
     off64_t erase_blk_size;
     off64_t logical_blk_size;
     char* sysfs_path;
@@ -118,8 +118,8 @@
     int max_comp_streams = 0;
     off64_t zram_size = 0;
     off64_t reserved_size = 0;
-    int file_contents_mode = 0;
-    int file_names_mode = 0;
+    std::string file_contents_mode;
+    std::string file_names_mode;
     off64_t erase_blk_size = 0;
     off64_t logical_blk_size = 0;
     std::string sysfs_path;
@@ -130,7 +130,7 @@
 
     // TODO: Remove this union once fstab_rec is deprecated. It only serves as a
     // convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
-    union {
+    union FsMgrFlags {
         uint64_t val;
         struct {
             // bit 0
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 4582401..9aa8efc 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -230,3 +230,121 @@
     EXPECT_EQ("none", fstab[6].mount_point);
     EXPECT_EQ("", fstab[6].fs_options);
 }
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ForceFdeOrFbe) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      forcefdeorfbe=/dir/key
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.force_fde_or_fbe = true;
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+
+    EXPECT_EQ("/dir/key", entry->key_loc);
+    EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      fileencryption=blah
+source none1       swap   defaults      fileencryption=software
+source none2       swap   defaults      fileencryption=aes-256-xts
+source none3       swap   defaults      fileencryption=adiantum
+source none4       swap   defaults      fileencryption=adiantum:aes-256-heh
+source none5       swap   defaults      fileencryption=ice
+source none6       swap   defaults      fileencryption=ice:blah
+source none7       swap   defaults      fileencryption=ice:aes-256-cts
+source none8       swap   defaults      fileencryption=ice:aes-256-heh
+source none9       swap   defaults      fileencryption=ice:adiantum
+source none10      swap   defaults      fileencryption=ice:adiantum:
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(11U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.file_encryption = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("adiantum", entry->file_contents_mode);
+    EXPECT_EQ("adiantum", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none4", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("adiantum", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-heh", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none5", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none6", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none7", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none8", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-heh", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none9", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("adiantum", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none10", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+}