Rewrite TWRP fstab flag processing
* Do not flip/flop between std::string and char* when no std::string
specific functions are applied.
* Remove the need to manually count flag string lengths
* Move checks for Display_Name, Storage_Name, and Backup_Display_Name
out of flag processing
Change-Id: I24d432c222124012b2a98d27598e42d0944f7da2
diff --git a/partition.cpp b/partition.cpp
index 4f66c5f..07d7171 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -110,6 +110,69 @@
{ 0, 0 },
};
+enum TW_FSTAB_FLAGS {
+ TWFLAG_DEFAULTS, // Retain position
+ TWFLAG_ANDSEC,
+ TWFLAG_BACKUP,
+ TWFLAG_BACKUPNAME,
+ TWFLAG_BLOCKSIZE,
+ TWFLAG_CANBEWIPED,
+ TWFLAG_CANENCRYPTBACKUP,
+ TWFLAG_DISPLAY,
+ TWFLAG_ENCRYPTABLE,
+ TWFLAG_FLASHIMG,
+ TWFLAG_FORCEENCRYPT,
+ TWFLAG_FSFLAGS,
+ TWFLAG_IGNOREBLKID,
+ TWFLAG_LENGTH,
+ TWFLAG_MOUNTTODECRYPT,
+ TWFLAG_REMOVABLE,
+ TWFLAG_RETAINLAYOUTVERSION,
+ TWFLAG_SETTINGSSTORAGE,
+ TWFLAG_STORAGE,
+ TWFLAG_STORAGENAME,
+ TWFLAG_SUBPARTITIONOF,
+ TWFLAG_SYMLINK,
+ TWFLAG_USERDATAENCRYPTBACKUP,
+ TWFLAG_USERMRF,
+ TWFLAG_WIPEDURINGFACTORYRESET,
+ TWFLAG_WIPEINGUI,
+};
+
+/* Flags without a trailing '=' are considered dual format flags and can be
+ * written as either 'flagname' or 'flagname=', where the character following
+ * the '=' is Y,y,1 for true and false otherwise.
+ */
+const struct flag_list tw_flags[] = {
+ { "andsec", TWFLAG_ANDSEC },
+ { "backup", TWFLAG_BACKUP },
+ { "backupname=", TWFLAG_BACKUPNAME },
+ { "blocksize=", TWFLAG_BLOCKSIZE },
+ { "canbewiped", TWFLAG_CANBEWIPED },
+ { "canencryptbackup", TWFLAG_CANENCRYPTBACKUP },
+ { "defaults", TWFLAG_DEFAULTS },
+ { "display=", TWFLAG_DISPLAY },
+ { "encryptable=", TWFLAG_ENCRYPTABLE },
+ { "flashimg", TWFLAG_FLASHIMG },
+ { "forceencrypt=", TWFLAG_FORCEENCRYPT },
+ { "fsflags=", TWFLAG_FSFLAGS },
+ { "ignoreblkid", TWFLAG_IGNOREBLKID },
+ { "length=", TWFLAG_LENGTH },
+ { "mounttodecrypt", TWFLAG_MOUNTTODECRYPT },
+ { "removable", TWFLAG_REMOVABLE },
+ { "retainlayoutversion", TWFLAG_RETAINLAYOUTVERSION },
+ { "settingsstorage", TWFLAG_SETTINGSSTORAGE },
+ { "storage", TWFLAG_STORAGE },
+ { "storagename=", TWFLAG_STORAGENAME },
+ { "subpartitionof=", TWFLAG_SUBPARTITIONOF },
+ { "symlink=", TWFLAG_SYMLINK },
+ { "userdataencryptbackup", TWFLAG_USERDATAENCRYPTBACKUP },
+ { "usermrf", TWFLAG_USERMRF },
+ { "wipeduringfactoryreset", TWFLAG_WIPEDURINGFACTORYRESET },
+ { "wipeingui", TWFLAG_WIPEINGUI },
+ { 0, 0 },
+};
+
TWPartition::TWPartition() {
Can_Be_Mounted = false;
Can_Be_Wiped = false;
@@ -174,9 +237,9 @@
bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) {
char full_line[MAX_FSTAB_LINE_LENGTH], item[MAX_FSTAB_LINE_LENGTH];
+ char twflags[MAX_FSTAB_LINE_LENGTH] = "";
int line_len = Line.size(), index = 0, item_index = 0;
char* ptr;
- string Flags;
strncpy(full_line, Line.c_str(), line_len);
bool skip = false;
@@ -241,8 +304,8 @@
} else if (strlen(ptr) > 6 && strncmp(ptr, "flags=", 6) == 0) {
// Custom flags, save for later so that new values aren't overwritten by defaults
ptr += 6;
- Flags = ptr;
- Process_Flags(Flags, Display_Error);
+ strlcpy(twflags, ptr, sizeof(twflags));
+ Process_TW_Flags(twflags, Display_Error);
} else if (strlen(ptr) == 4 && (strncmp(ptr, "NULL", 4) == 0 || strncmp(ptr, "null", 4) == 0 || strncmp(ptr, "null", 4) == 0)) {
// Do nothing
} else {
@@ -419,9 +482,33 @@
}
}
- // Process any custom flags
- if (Flags.size() > 0)
- Process_Flags(Flags, Display_Error);
+ // Process TWRP fstab flags
+ if (strlen(twflags) > 0) {
+ string Prev_Display_Name = Display_Name;
+ string Prev_Storage_Name = Storage_Name;
+ string Prev_Backup_Display_Name = Backup_Display_Name;
+ Display_Name = "";
+ Storage_Name = "";
+ Backup_Display_Name = "";
+
+ Process_TW_Flags(twflags, Display_Error);
+
+ bool has_display_name = !Display_Name.empty();
+ bool has_storage_name = !Storage_Name.empty();
+ bool has_backup_name = !Backup_Display_Name.empty();
+ if (!has_display_name) Display_Name = Prev_Display_Name;
+ if (!has_storage_name) Storage_Name = Prev_Storage_Name;
+ if (!has_backup_name) Backup_Display_Name = Prev_Backup_Display_Name;
+
+ if (has_display_name && !has_storage_name)
+ Storage_Name = Display_Name;
+ if (!has_display_name && has_storage_name)
+ Display_Name = Storage_Name;
+ if (has_display_name && !has_backup_name && Backup_Display_Name != "Android Secure")
+ Backup_Display_Name = Display_Name;
+ if (!has_display_name && has_backup_name)
+ Display_Name = Backup_Display_Name;
+ }
return true;
}
@@ -457,175 +544,184 @@
return true;
}
-bool TWPartition::Process_Flags(string Flags, bool Display_Error) {
- char flags[MAX_FSTAB_LINE_LENGTH];
- int flags_len, index = 0, ptr_len;
- char* ptr;
- bool skip = false, has_display_name = false, has_storage_name = false, has_backup_name = false;
+void TWPartition::Apply_TW_Flag(const unsigned flag, const char* str, const bool val) {
+ switch (flag) {
+ case TWFLAG_ANDSEC:
+ Has_Android_Secure = val;
+ break;
+ case TWFLAG_BACKUP:
+ Can_Be_Backed_Up = val;
+ break;
+ case TWFLAG_BACKUPNAME:
+ Backup_Display_Name = str;
+ break;
+ case TWFLAG_BLOCKSIZE:
+ Format_Block_Size = (unsigned long)(atol(str));
+ break;
+ case TWFLAG_CANBEWIPED:
+ Can_Be_Wiped = val;
+ break;
+ case TWFLAG_CANENCRYPTBACKUP:
+ Can_Encrypt_Backup = val;
+ break;
+ case TWFLAG_DEFAULTS:
+ // Do nothing
+ break;
+ case TWFLAG_DISPLAY:
+ Display_Name = str;
+ break;
+ case TWFLAG_ENCRYPTABLE:
+ case TWFLAG_FORCEENCRYPT:
+ Crypto_Key_Location = str;
+ break;
+ case TWFLAG_FLASHIMG:
+ Can_Flash_Img = val;
+ break;
+ case TWFLAG_FSFLAGS:
+ Mount_Options = str;
+ Process_FS_Flags(Mount_Options, Mount_Flags);
+ break;
+ case TWFLAG_IGNOREBLKID:
+ Ignore_Blkid = val;
+ break;
+ case TWFLAG_LENGTH:
+ Length = atoi(str);
+ break;
+ case TWFLAG_MOUNTTODECRYPT:
+ Mount_To_Decrypt = val;
+ break;
+ case TWFLAG_REMOVABLE:
+ Removable = val;
+ break;
+ case TWFLAG_RETAINLAYOUTVERSION:
+ Retain_Layout_Version = val;
+ break;
+ case TWFLAG_SETTINGSSTORAGE:
+ Is_Settings_Storage = val;
+ if (Is_Settings_Storage)
+ Is_Storage = true;
+ break;
+ case TWFLAG_STORAGE:
+ Is_Storage = val;
+ break;
+ case TWFLAG_STORAGENAME:
+ Storage_Name = str;
+ break;
+ case TWFLAG_SUBPARTITIONOF:
+ Is_SubPartition = true;
+ SubPartition_Of = str;
+ break;
+ case TWFLAG_SYMLINK:
+ Symlink_Path = str;
+ break;
+ case TWFLAG_USERDATAENCRYPTBACKUP:
+ Use_Userdata_Encryption = val;
+ if (Use_Userdata_Encryption)
+ Can_Encrypt_Backup = true;
+ break;
+ case TWFLAG_USERMRF:
+ Use_Rm_Rf = val;
+ break;
+ case TWFLAG_WIPEDURINGFACTORYRESET:
+ Wipe_During_Factory_Reset = val;
+ if (Wipe_During_Factory_Reset) {
+ Can_Be_Wiped = true;
+ Wipe_Available_in_GUI = true;
+ }
+ break;
+ case TWFLAG_WIPEINGUI:
+ Wipe_Available_in_GUI = val;
+ if (Wipe_Available_in_GUI)
+ Can_Be_Wiped = true;
+ break;
+ default:
+ // Should not get here
+ LOGINFO("Flag identified for processing, but later unmatched: %i\n", flag);
+ break;
+ }
+}
- strcpy(flags, Flags.c_str());
- flags_len = Flags.size();
- for (index = 0; index < flags_len; index++) {
- if (flags[index] == 34)
+void TWPartition::Process_TW_Flags(char *flags, bool Display_Error) {
+ char separator[2] = {'\n', 0};
+ char *ptr, *savep;
+
+ // Semicolons within double-quotes are not forbidden, so replace
+ // only the semicolons intended as separators with '\n' for strtok
+ for (unsigned i = 0, skip = 0; i < strlen(flags); i++) {
+ if (flags[i] == '\"')
skip = !skip;
- if (!skip && flags[index] == ';')
- flags[index] = '\0';
+ if (!skip && flags[i] == ';')
+ flags[i] = separator[0];
}
- index = 0;
- while (index < flags_len) {
- while (index < flags_len && flags[index] == '\0')
- index++;
- if (index >= flags_len)
- continue;
- ptr = flags + index;
- ptr_len = strlen(ptr);
- if (strcmp(ptr, "removable") == 0) {
- Removable = true;
- } else if (strncmp(ptr, "storage", 7) == 0) {
- if (ptr_len == 7) {
- Is_Storage = true;
- } else if (ptr_len == 9) {
- ptr += 8;
- if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
- LOGINFO("storage set to true\n");
- Is_Storage = true;
- } else {
- LOGINFO("storage set to false\n");
- Is_Storage = false;
- }
- }
- } else if (strcmp(ptr, "settingsstorage") == 0) {
- Is_Storage = true;
- Is_Settings_Storage = true;
- } else if (strcmp(ptr, "andsec") == 0) {
- Has_Android_Secure = true;
- } else if (strcmp(ptr, "canbewiped") == 0) {
- Can_Be_Wiped = true;
- } else if (strcmp(ptr, "usermrf") == 0) {
- Use_Rm_Rf = true;
- } else if (ptr_len > 7 && strncmp(ptr, "backup=", 7) == 0) {
- ptr += 7;
- if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y')
- Can_Be_Backed_Up = true;
- else
- Can_Be_Backed_Up = false;
- } else if (strcmp(ptr, "wipeingui") == 0) {
- Can_Be_Wiped = true;
- Wipe_Available_in_GUI = true;
- } else if (strcmp(ptr, "wipeduringfactoryreset") == 0) {
- Can_Be_Wiped = true;
- Wipe_Available_in_GUI = true;
- Wipe_During_Factory_Reset = true;
- } else if (ptr_len > 15 && strncmp(ptr, "subpartitionof=", 15) == 0) {
- ptr += 15;
- Is_SubPartition = true;
- SubPartition_Of = ptr;
- } else if (strcmp(ptr, "ignoreblkid") == 0) {
- Ignore_Blkid = true;
- } else if (strcmp(ptr, "retainlayoutversion") == 0) {
- Retain_Layout_Version = true;
- } else if (ptr_len > 8 && strncmp(ptr, "symlink=", 8) == 0) {
- ptr += 8;
- Symlink_Path = ptr;
- } else if (ptr_len > 8 && strncmp(ptr, "display=", 8) == 0) {
- has_display_name = true;
- ptr += 8;
- if (*ptr == '\"') ptr++;
- Display_Name = ptr;
- if (Display_Name.substr(Display_Name.size() - 1, 1) == "\"") {
- Display_Name.resize(Display_Name.size() - 1);
- }
- } else if (ptr_len > 12 && strncmp(ptr, "storagename=", 12) == 0) {
- has_storage_name = true;
- ptr += 12;
- if (*ptr == '\"') ptr++;
- Storage_Name = ptr;
- if (Storage_Name.substr(Storage_Name.size() - 1, 1) == "\"") {
- Storage_Name.resize(Storage_Name.size() - 1);
- }
- } else if (ptr_len > 11 && strncmp(ptr, "backupname=", 11) == 0) {
- has_backup_name = true;
- ptr += 11;
- if (*ptr == '\"') ptr++;
- Backup_Display_Name = ptr;
- if (Backup_Display_Name.substr(Backup_Display_Name.size() - 1, 1) == "\"") {
- Backup_Display_Name.resize(Backup_Display_Name.size() - 1);
- }
- } else if (ptr_len > 10 && strncmp(ptr, "blocksize=", 10) == 0) {
- ptr += 10;
- Format_Block_Size = (unsigned long)(atol(ptr));
- } else if (ptr_len > 7 && strncmp(ptr, "length=", 7) == 0) {
- ptr += 7;
- Length = atoi(ptr);
- } else if (ptr_len > 17 && strncmp(ptr, "canencryptbackup=", 17) == 0) {
- ptr += 17;
- if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y')
- Can_Encrypt_Backup = true;
- else
- Can_Encrypt_Backup = false;
- } else if (ptr_len > 22 && strncmp(ptr, "userdataencryptbackup=", 22) == 0) {
- ptr += 22;
- if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
- Can_Encrypt_Backup = true;
- Use_Userdata_Encryption = true;
- } else {
- Use_Userdata_Encryption = false;
- }
- } else if (ptr_len > 8 && strncmp(ptr, "fsflags=", 8) == 0) {
- ptr += 8;
- if (*ptr == '\"') ptr++;
+ // Avoid issues with potentially nested strtok by using strtok_r
+ ptr = strtok_r(flags, separator, &savep);
+ while (ptr) {
+ int ptr_len = strlen(ptr);
+ const struct flag_list* tw_flag = tw_flags;
- Mount_Options = ptr;
- if (Mount_Options.substr(Mount_Options.size() - 1, 1) == "\"") {
- Mount_Options.resize(Mount_Options.size() - 1);
- }
- Process_FS_Flags(Mount_Options, Mount_Flags);
- } else if (ptr_len > 12 && strncmp(ptr, "encryptable=", 12) == 0) {
- ptr += 12;
- if (*ptr == '\"') ptr++;
- Crypto_Key_Location = ptr;
- if (Crypto_Key_Location.substr(Crypto_Key_Location.size() - 1, 1) == "\"") {
- Crypto_Key_Location.resize(Crypto_Key_Location.size() - 1);
- }
- } else if (ptr_len > 13 && strncmp(ptr, "forceencrypt=", 13) == 0) {
- ptr += 13;
- if (*ptr == '\"') ptr++;
- Crypto_Key_Location = ptr;
- if (Crypto_Key_Location.substr(Crypto_Key_Location.size() - 1, 1) == "\"") {
- Crypto_Key_Location.resize(Crypto_Key_Location.size() - 1);
- }
- } else if (ptr_len > 8 && strncmp(ptr, "mounttodecrypt", 14) == 0) {
- Mount_To_Decrypt = true;
- } else if (strncmp(ptr, "flashimg", 8) == 0) {
- if (ptr_len == 8) {
- Can_Flash_Img = true;
- } else if (ptr_len == 10) {
- ptr += 9;
- if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
- Can_Flash_Img = true;
+ for (; tw_flag->name; tw_flag++) {
+ int flag_len = strlen(tw_flag->name);
+
+ if (strncmp(ptr, tw_flag->name, flag_len) == 0) {
+ bool flag_val = false;
+
+ if (ptr_len > flag_len && (tw_flag->name)[flag_len-1] != '='
+ && ptr[flag_len] != '=') {
+ // Handle flags with same starting string
+ // (e.g. backup and backupname)
+ continue;
+ } else if (ptr_len > flag_len && ptr[flag_len] == '=') {
+ // Handle flags with dual format: Part 1
+ // (e.g. backup and backup=y. backup=y handled here)
+ ptr += flag_len + 1;
+ TWFunc::Strip_Quotes(ptr);
+ // Skip flags with empty argument
+ // (e.g. backup=)
+ if (strlen(ptr) == 0) {
+ LOGINFO("Flag missing argument or should not include '=': %s=\n", tw_flag->name);
+ break;
+ }
+ flag_val = strchr("yY1", *ptr) != NULL;
+ } else if (ptr_len == flag_len
+ && (tw_flag->name)[flag_len-1] == '=') {
+ // Skip flags missing argument after =
+ // (e.g. backupname=)
+ LOGINFO("Flag missing argument: %s\n", tw_flag->name);
+ break;
+ } else if (ptr_len > flag_len
+ && (tw_flag->name)[flag_len-1] == '=') {
+ // Handle arguments to flags
+ // (e.g. backupname="My Stuff")
+ ptr += flag_len;
+ TWFunc::Strip_Quotes(ptr);
+ // Skip flags with empty argument
+ // (e.g. backupname="")
+ if (strlen(ptr) == 0) {
+ LOGINFO("Flag missing argument: %s\n", tw_flag->name);
+ break;
+ }
+ } else if (ptr_len == flag_len) {
+ // Handle flags with dual format: Part 2
+ // (e.g. backup and backup=y. backup handled here)
+ flag_val = true;
} else {
- Can_Flash_Img = false;
+ LOGINFO("Flag matched, but could not be processed: %s\n", ptr);
+ break;
}
+
+ Apply_TW_Flag(tw_flag->flag, ptr, flag_val);
+ break;
}
- } else {
+ }
+ if (tw_flag->name == 0) {
if (Display_Error)
LOGERR("Unhandled flag: '%s'\n", ptr);
else
LOGINFO("Unhandled flag: '%s'\n", ptr);
}
- while (index < flags_len && flags[index] != '\0')
- index++;
+ ptr = strtok_r(NULL, separator, &savep);
}
- if (has_display_name && !has_storage_name)
- Storage_Name = Display_Name;
- if (!has_display_name && has_storage_name)
- Display_Name = Storage_Name;
- if (has_display_name && !has_backup_name && Backup_Display_Name != "Android Secure")
- Backup_Display_Name = Display_Name;
- if (!has_display_name && has_backup_name)
- Display_Name = Backup_Display_Name;
- return true;
}
bool TWPartition::Is_File_System(string File_System) {
diff --git a/partitions.hpp b/partitions.hpp
index 035acf0..91c8036 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -98,7 +98,8 @@
bool Process_Fstab_Line(string Line, bool Display_Error); // Processes a fstab line
void Find_Actual_Block_Device(); // Determines the correct block device and stores it in Actual_Block_Device
- bool Process_Flags(string Flags, bool Display_Error); // Process custom fstab flags
+ void Apply_TW_Flag(const unsigned flag, const char* str, const bool val); // Apply custom twrp fstab flags
+ void Process_TW_Flags(char *flags, bool Display_Error); // Process custom twrp fstab flags
bool Process_FS_Flags(string& Options, int& Flags); // Process standard fstab fs flags
bool Is_File_System(string File_System); // Checks to see if the file system given is considered a file system
bool Is_Image(string File_System); // Checks to see if the file system given is considered an image
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 8d85ccf..1c633e7 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -305,6 +305,13 @@
return res;
}
+void TWFunc::Strip_Quotes(char* &str) {
+ if (strlen(str) > 0 && str[0] == '\"')
+ str++;
+ if (strlen(str) > 0 && str[strlen(str)-1] == '\"')
+ str[strlen(str)-1] = 0;
+}
+
vector<string> TWFunc::split_string(const string &in, char del, bool skip_empty) {
vector<string> res;
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 6c33c5e..3f9b2ff 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -50,6 +50,7 @@
static int Try_Decrypting_File(string fn, string password); // -1 for some error, 0 for failed to decrypt, 1 for decrypted, 3 for decrypted and found gzip format
static unsigned long Get_File_Size(const string& Path); // Returns the size of a file
static std::string Remove_Trailing_Slashes(const std::string& path, bool leaveLast = false); // Normalizes the path, e.g /data//media/ -> /data/media
+ static void Strip_Quotes(char* &str); // Remove leading & trailing double-quotes from a string
static vector<string> split_string(const string &in, char del, bool skip_empty);
static timespec timespec_diff(timespec& start, timespec& end); // Return a diff for 2 times
static int32_t timespec_diff_ms(timespec& start, timespec& end); // Returns diff in ms