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 <[email protected]>
---
originated from:
https://github.com/hsiangkao/erofs-utils/commit/e30bee2993d35350406ed8b0e0bfd6e580edc734

with some cleanup, and haven't rebuilt with
Android environment yet.

 include/erofs/config.h   | 12 +++++++++
 include/erofs/internal.h |  3 +++
 lib/inode.c              | 49 +++++++++++++++++++++++++++++++++++
 lib/xattr.c              | 56 ++++++++++++++++++++++++++++++++++++++++
 mkfs/main.c              | 29 ++++++++++++++++++++-
 5 files changed, 148 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..0986e4674d81 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,52 @@ err:
        return ret;
 }
 
+#ifdef WITH_ANDROID
+static struct vfs_cap_data __set_caps(uint64_t capabilities)
+{
+       struct vfs_cap_data cap_data = {0};
+
+       if (capabilities == 0)
+               return cap_data;
+
+       cap_data.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
+       cap_data.data[0].permitted = (uint32_t) capabilities;
+       cap_data.data[0].inheritable = 0;
+       cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
+       cap_data.data[1].inheritable = 0;
+       return cap_data;
+}
+
+static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
+{
+       if (inode->capabilities) {
+               unsigned int len[2];
+               char *kvbuf;
+               struct vfs_cap_data caps;
+               struct xattr_item *item;
+
+               len[0] = sizeof("capability") - 1;
+               len[1] = sizeof(struct vfs_cap_data);
+               kvbuf = malloc(len[0] + len[1]);
+               if (!kvbuf)
+                       return -ENOMEM;
+
+               memcpy(kvbuf, "capability", len[0]);
+               caps = __set_caps(inode->capabilities);
+               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) {
+                       ret = erofs_xattr_add(ixattrs, item);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+       return 0;
+}
+#endif
+
 int erofs_prepare_xattr_ibody(struct erofs_inode *inode)
 {
        int ret;
@@ -366,6 +418,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

Reply via email to