[PATCH v2] AOSP: erofs-utils: add fs_config support

Gao Xiang hsiangkao at aol.com
Tue Sep 29 15:13:02 AEST 2020


So that mkfs can directly generate images with fs_config.
All code for AOSP is wraped up with WITH_ANDROID macro.

Signed-off-by: Gao Xiang <hsiangkao at aol.com>
---
changes since v1:
 - fix compile issues on Android / Linux build;
 - tested with Android system booting;

 include/erofs/config.h   | 12 ++++++++++
 include/erofs/internal.h |  3 +++
 lib/inode.c              | 49 +++++++++++++++++++++++++++++++++++++
 lib/xattr.c              | 52 ++++++++++++++++++++++++++++++++++++++++
 mkfs/main.c              | 29 +++++++++++++++++++++-
 5 files changed, 144 insertions(+), 1 deletion(-)

diff --git a/include/erofs/config.h b/include/erofs/config.h
index 2f0974900be1..9902a089ab46 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -17,6 +17,13 @@
 #include <selinux/label.h>
 #endif
 
+#ifdef WITH_ANDROID
+#include <selinux/android.h>
+#include <private/android_filesystem_config.h>
+#include <private/canned_fs_config.h>
+#include <private/fs_config.h>
+#endif
+
 enum {
 	FORCE_INODE_COMPACT = 1,
 	FORCE_INODE_EXTENDED,
@@ -40,6 +47,11 @@ struct erofs_configure {
 	/* < 0, xattr disabled and INT_MAX, always use inline xattrs */
 	int c_inline_xattr_tolerance;
 	u64 c_unix_timestamp;
+#ifdef WITH_ANDROID
+	char *mount_point;
+	char *target_out_path;
+	char *fs_config_file;
+#endif
 };
 
 extern struct erofs_configure cfg;
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 41da189ffac1..bc77c43719e8 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -127,6 +127,9 @@ struct erofs_inode {
 
 	void *idata;
 	void *compressmeta;
+#ifdef WITH_ANDROID
+	uint64_t capabilities;
+#endif
 };
 
 static inline bool is_inode_layout_compression(struct erofs_inode *inode)
diff --git a/lib/inode.c b/lib/inode.c
index 5013184e66bf..597cbc7fc6dd 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -673,10 +673,59 @@ static u32 erofs_new_encode_dev(dev_t dev)
 	return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
 }
 
+#ifdef WITH_ANDROID
+int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
+			       struct stat64 *st,
+			       const char *path)
+{
+	/* filesystem_config does not preserve file type bits */
+	mode_t stat_file_type_mask = st->st_mode & S_IFMT;
+	unsigned int uid = 0, gid = 0, mode = 0;
+	char *fspath;
+
+	inode->capabilities = 0;
+	if (cfg.fs_config_file)
+		canned_fs_config(erofs_fspath(path),
+				 S_ISDIR(st->st_mode),
+				 cfg.target_out_path,
+				 &uid, &gid, &mode, &inode->capabilities);
+	else if (cfg.mount_point) {
+		if (asprintf(&fspath, "%s/%s", cfg.mount_point,
+			     erofs_fspath(path)) <= 0)
+			return -ENOMEM;
+
+		fs_config(fspath, S_ISDIR(st->st_mode),
+			  cfg.target_out_path,
+			  &uid, &gid, &mode, &inode->capabilities);
+		free(fspath);
+	}
+	st->st_uid = uid;
+	st->st_gid = gid;
+	st->st_mode = mode | stat_file_type_mask;
+
+	erofs_dbg("/%s -> mode = 0x%x, uid = 0x%x, gid = 0x%x, "
+		  "capabilities = 0x%" PRIx64 "\n",
+		  erofs_fspath(path),
+		  mode, uid, gid, inode->capabilities);
+	return 0;
+}
+#else
+static int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
+				      struct stat64 *st,
+				      const char *path)
+{
+	return 0;
+}
+#endif
+
 int erofs_fill_inode(struct erofs_inode *inode,
 		     struct stat64 *st,
 		     const char *path)
 {
+	int err = erofs_droid_inode_fsconfig(inode, st, path);
+	if (err)
+		return err;
+
 	inode->i_mode = st->st_mode;
 	inode->i_uid = st->st_uid;
 	inode->i_gid = st->st_gid;
diff --git a/lib/xattr.c b/lib/xattr.c
index 769ab9c716d0..b9ac223cc746 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -196,6 +196,12 @@ static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
 		unsigned int len[2];
 		char *kvbuf, *fspath;
 
+#ifdef WITH_ANDROID
+		if (cfg.mount_point)
+			ret = asprintf(&fspath, "/%s/%s", cfg.mount_point,
+				       erofs_fspath(srcpath));
+		else
+#endif
 		ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
 		if (ret <= 0)
 			return ERR_PTR(-ENOMEM);
@@ -352,6 +358,48 @@ err:
 	return ret;
 }
 
+#ifdef WITH_ANDROID
+static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
+{
+	const u64 capabilities = inode->capabilities;
+	char *kvbuf;
+	unsigned int len[2];
+	struct vfs_cap_data caps;
+	struct xattr_item *item;
+
+	if (!capabilities)
+		return 0;
+
+	len[0] = sizeof("capability") - 1;
+	len[1] = sizeof(caps);
+
+	kvbuf = malloc(len[0] + len[1]);
+	if (!kvbuf)
+		return -ENOMEM;
+
+	memcpy(kvbuf, "capability", len[0]);
+	caps.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
+	caps.data[0].permitted = (u32) capabilities;
+	caps.data[0].inheritable = 0;
+	caps.data[1].permitted = (u32) (capabilities >> 32);
+	caps.data[1].inheritable = 0;
+	memcpy(kvbuf + len[0], &caps, len[1]);
+
+	item = get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
+	if (IS_ERR(item))
+		return PTR_ERR(item);
+	if (!item)
+		return 0;
+
+	return erofs_xattr_add(&inode->i_xattrs, item);
+}
+#else
+static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
+{
+	return 0;
+}
+#endif
+
 int erofs_prepare_xattr_ibody(struct erofs_inode *inode)
 {
 	int ret;
@@ -366,6 +414,10 @@ int erofs_prepare_xattr_ibody(struct erofs_inode *inode)
 	if (ret < 0)
 		return ret;
 
+	ret = erofs_droid_xattr_set_caps(inode);
+	if (ret < 0)
+		return ret;
+
 	if (list_empty(ixattrs))
 		return 0;
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 94bf1e6a2425..191003409b2f 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -35,6 +35,11 @@ static struct option long_options[] = {
 	{"exclude-regex", required_argument, NULL, 3},
 #ifdef HAVE_LIBSELINUX
 	{"file-contexts", required_argument, NULL, 4},
+#endif
+#ifdef WITH_ANDROID
+	{"mount-point", required_argument, NULL, 10},
+	{"product-out", required_argument, NULL, 11},
+	{"fs-config-file", required_argument, NULL, 12},
 #endif
 	{0, 0, 0, 0},
 };
@@ -210,7 +215,21 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 			if (opt && opt != -EBUSY)
 				return opt;
 			break;
-
+#ifdef WITH_ANDROID
+		case 10:
+			cfg.mount_point = optarg;
+			/* all trailing '/' should be deleted */
+			opt = strlen(cfg.mount_point);
+			if (opt && optarg[opt - 1] == '/')
+				optarg[opt - 1] = '\0';
+			break;
+		case 11:
+			cfg.target_out_path = optarg;
+			break;
+		case 12:
+			cfg.fs_config_file = optarg;
+			break;
+#endif
 		case 1:
 			usage();
 			exit(0);
@@ -404,6 +423,14 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
+#ifdef WITH_ANDROID
+	if (cfg.fs_config_file &&
+	    load_canned_fs_config(cfg.fs_config_file) < 0) {
+		erofs_err("failed to load fs config %s", cfg.fs_config_file);
+		return 1;
+	}
+#endif
+
 	erofs_show_config();
 	erofs_set_fs_root(cfg.c_src_path);
 
-- 
2.24.0



More information about the Linux-erofs mailing list