Allow passing fs_config file for generating mksquashfs

BUG: 27467028
Change-Id: I5133d15b0eed0860dae17b72bae7d908cf901d93
Signed-off-by: Mohamad Ayyash <mkayyash@google.com>
diff --git a/squashfs-tools/android.c b/squashfs-tools/android.c
index 7bba052..eeef2aa 100644
--- a/squashfs-tools/android.c
+++ b/squashfs-tools/android.c
@@ -29,6 +29,7 @@
 
 #include "android.h"
 #include "private/android_filesystem_config.h"
+#include "private/canned_fs_config.h"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
@@ -42,9 +43,14 @@
     strcat(*mounted_path, subpath);
 }
 
-void android_fs_config(const char *path, struct stat *stat, const char *target_out_path, uint64_t *capabilities) {
-    fs_config(path, S_ISDIR(stat->st_mode), target_out_path,
-              &stat->st_uid, &stat->st_gid, &stat->st_mode, capabilities);
+void android_fs_config(fs_config_func_t fs_config_func, const char *path, struct stat *stat,
+        const char *target_out_path, uint64_t *capabilities) {
+    // filesystem_config does not preserve file type bits
+    mode_t stat_file_type_mask = stat->st_mode & S_IFMT;
+    if (fs_config_func)
+        fs_config_func(path, S_ISDIR(stat->st_mode), target_out_path,
+                  &stat->st_uid, &stat->st_gid, &stat->st_mode, capabilities);
+    stat->st_mode |= stat_file_type_mask;
 }
 
 
diff --git a/squashfs-tools/android.h b/squashfs-tools/android.h
index 656b628..998f710 100644
--- a/squashfs-tools/android.h
+++ b/squashfs-tools/android.h
@@ -18,9 +18,11 @@
 #define _ANDROID_H_
 
 #include <stdint.h>
+typedef void (*fs_config_func_t)(const char *path, int dir, const char *target_out_path,
+                unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
 
 void alloc_mounted_path(const char *mount_point, const char *subpath, char **mounted_path);
-void android_fs_config(const char *path, struct stat *stat, const char *target_out_path, uint64_t *capabilities);
+void android_fs_config(fs_config_func_t fs_config_func, const char *path, struct stat *stat, const char *target_out_path, uint64_t *capabilities);
 struct selabel_handle *get_sehnd(const char *context_file);
 char *set_selabel(const char *path, unsigned int mode, struct selabel_handle *sehnd);
 struct vfs_cap_data set_caps(uint64_t capabilities);
diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c
index 2c1492a..033bc8e 100644
--- a/squashfs-tools/mksquashfs.c
+++ b/squashfs-tools/mksquashfs.c
@@ -84,10 +84,13 @@
 /* ANDROID CHANGES START*/
 #ifdef ANDROID
 #include "android.h"
+#include "private/android_filesystem_config.h"
+#include "private/canned_fs_config.h"
 int android_config = FALSE;
 char *context_file = NULL;
 char *mount_point = NULL;
 char *target_out_path = NULL;
+fs_config_func_t fs_config_func = NULL;
 #endif
 /* ANDROID CHANGES END */
 
@@ -3069,10 +3072,10 @@
 			rel_path = mounted_path;
 			while (rel_path && *rel_path == '/')
 				rel_path++;
-			android_fs_config(rel_path, &inode_info->buf, target_out_path, &dir_ent->capabilities);
+			android_fs_config(fs_config_func, rel_path, &inode_info->buf, target_out_path, &dir_ent->capabilities);
 			free(mounted_path);
 		} else {
-			android_fs_config(pathname(dir_ent), &inode_info->buf, target_out_path, &dir_ent->capabilities);
+			android_fs_config(fs_config_func, pathname(dir_ent), &inode_info->buf, target_out_path, &dir_ent->capabilities);
 		}
 	}
 #endif
@@ -3167,9 +3170,9 @@
 #ifdef ANDROID
 		if (android_config) {
 			if (mount_point)
-				android_fs_config(mount_point, &buf, target_out_path, &caps);
+				android_fs_config(fs_config_func, mount_point, &buf, target_out_path, &caps);
 			else
-				android_fs_config(pathname, &buf, target_out_path, &caps);
+				android_fs_config(fs_config_func, pathname, &buf, target_out_path, &caps);
 		}
 #endif
 /* ANDROID CHANGES END */
@@ -5210,6 +5213,11 @@
 	int progress = TRUE;
 	int force_progress = FALSE;
 	struct file_buffer **fragment = NULL;
+/* ANDROID CHANGES START*/
+#ifdef ANDROID
+	const char *fs_config_file = NULL;
+#endif
+/* ANDROID CHANGES END */
 
 	if(argc > 1 && strcmp(argv[1], "-version") == 0) {
 		VERSION();
@@ -5619,6 +5627,14 @@
 			}
 			context_file = argv[i];
 		}
+		else if(strcmp(argv[i], "-fs-config-file") == 0) {
+			if(++i == argc) {
+				ERROR("%s: -fs-config-file: missing file name\n",
+					argv[0]);
+				exit(1);
+			}
+			fs_config_file = argv[i];
+		}
 #endif
 /* ANDROID CHANGES END */
 		else if(strcmp(argv[i], "-nopad") == 0)
@@ -5696,6 +5712,8 @@
 			ERROR("-context-file <file>\tApply selinux security "
 				"xattrs from context-file instead\n\t\t\t"
 				"of reading xattrs from file system\n");
+			ERROR("-fs-config-file <file>\tAndroid specific "
+				"filesystem config file\n");
 #endif
 /* ANDROID CHANGES END */
 			ERROR("-noI\t\t\tdo not compress inode table\n");
@@ -5798,6 +5816,20 @@
 		}
 	}
 
+/* ANDROID CHANGES START*/
+#ifdef ANDROID
+	if (fs_config_file) {
+		if (load_canned_fs_config(fs_config_file) < 0) {
+			fprintf(stderr, "failed to load %s\n", fs_config_file);
+			exit(1);
+		}
+		fs_config_func = canned_fs_config;
+	} else if (mount_point) {
+		fs_config_func = fs_config;
+	}
+#endif
+/* ANDROID CHANGES END */
+
 	/*
 	 * Some compressors may need the options to be checked for validity
 	 * once all the options have been processed