Add 'newcx' format that adds extended attributes and increased size of
c_mtime and c_filesize fields.

Refer to Documentation/early-userspace/buffer-format.txt for detailed
format description.

Signed-off-by: Taras Kondratiuk <takon...@cisco.com>
---
 init/initramfs.c | 121 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 96 insertions(+), 25 deletions(-)

diff --git a/init/initramfs.c b/init/initramfs.c
index 7f0bbfde94e3..0407e199352e 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -54,6 +54,7 @@ static void __init error(char *x)
 /* link hash */
 
 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
+#define X_ALIGN(len) ((len + 3) & ~3)
 
 static __initdata struct hash {
        int ino, minor, major;
@@ -109,14 +110,11 @@ static void __init free_hash(void)
        }
 }
 
-static long __init do_utime(char *filename, time64_t mtime)
+static long __init do_utime(char *filename, struct timespec64 *mtime)
 {
        struct timespec64 t[2];
 
-       t[0].tv_sec = mtime;
-       t[0].tv_nsec = 0;
-       t[1].tv_sec = mtime;
-       t[1].tv_nsec = 0;
+       t[0] = t[1] = *mtime;
 
        return do_utimes(AT_FDCWD, filename, t, AT_SYMLINK_NOFOLLOW);
 }
@@ -125,17 +123,17 @@ static __initdata LIST_HEAD(dir_list);
 struct dir_entry {
        struct list_head list;
        char *name;
-       time64_t mtime;
+       struct timespec64 mtime;
 };
 
-static void __init dir_add(const char *name, time64_t mtime)
+static void __init dir_add(const char *name, struct timespec64 *mtime)
 {
        struct dir_entry *de = kmalloc(sizeof(struct dir_entry), GFP_KERNEL);
        if (!de)
                panic("can't allocate dir_entry buffer");
        INIT_LIST_HEAD(&de->list);
        de->name = kstrdup(name, GFP_KERNEL);
-       de->mtime = mtime;
+       de->mtime = *mtime;
        list_add(&de->list, &dir_list);
 }
 
@@ -144,17 +142,18 @@ static void __init dir_utime(void)
        struct dir_entry *de, *tmp;
        list_for_each_entry_safe(de, tmp, &dir_list, list) {
                list_del(&de->list);
-               do_utime(de->name, de->mtime);
+               do_utime(de->name, &de->mtime);
                kfree(de->name);
                kfree(de);
        }
 }
 
 /* cpio header parsing */
-static __initdata time64_t mtime;
+static __initdata struct timespec64 mtime;
 static __initdata u32 ino, major, minor, nlink, rmajor, rminor;
 static __initdata umode_t mode;
-static __initdata u32 body_len, name_len;
+static __initdata u32 name_len, xattr_len;
+static __initdata u64 body_len;
 static __initdata uid_t uid;
 static __initdata gid_t gid;
 static __initdata u32 mode_u32;
@@ -167,6 +166,12 @@ struct cpio_hdr_field {
        const char *name;
 };
 
+static __initdata enum cpio_format {
+       CPIO_NO_MAGIC,
+       CPIO_NEWC,
+       CPIO_NEWCX,
+} cpio_format;
+
 #define HDR_FIELD(type, field, variable) \
        { .offset = offsetof(type, field) + \
          BUILD_BUG_ON_ZERO(sizeof(*(variable))*2 < FIELD_SIZEOF(type, field)),\
@@ -177,9 +182,11 @@ struct cpio_hdr_field {
 
 #define NEWC_FIELD(field, variable) \
                HDR_FIELD(struct cpio_newc_header, field, variable)
+#define NEWCX_FIELD(field, variable) \
+               HDR_FIELD(struct cpio_newcx_header, field, variable)
 
-#define CPIO_MAX_HEADER_SIZE sizeof(struct cpio_newc_header)
-#define CPIO_MAX_FIELD_SIZE 8
+#define CPIO_MAX_HEADER_SIZE sizeof(struct cpio_newcx_header)
+#define CPIO_MAX_FIELD_SIZE 16
 #define CPIO_MAGIC_SIZE 6
 
 struct cpio_newc_header {
@@ -204,7 +211,7 @@ static struct cpio_hdr_field cpio_newc_header_info[] 
__initdata = {
        NEWC_FIELD(c_uid, &uid),
        NEWC_FIELD(c_gid, &gid),
        NEWC_FIELD(c_nlink, &nlink),
-       NEWC_FIELD(c_mtime, &mtime),
+       NEWC_FIELD(c_mtime, &mtime.tv_sec),
        NEWC_FIELD(c_filesize, &body_len),
        NEWC_FIELD(c_devmajor, &major),
        NEWC_FIELD(c_devminor, &minor),
@@ -214,10 +221,46 @@ static struct cpio_hdr_field cpio_newc_header_info[] 
__initdata = {
        { 0 },
 };
 
+struct cpio_newcx_header {
+       char    c_ino[8];
+       char    c_mode[8];
+       char    c_uid[8];
+       char    c_gid[8];
+       char    c_nlink[8];
+       char    c_mtime[16];
+       char    c_mtime_nsec[8];
+       char    c_filesize[16];
+       char    c_devmajor[8];
+       char    c_devminor[8];
+       char    c_rdevmajor[8];
+       char    c_rdevminor[8];
+       char    c_namesize[8];
+       char    c_xattrsize[8];
+};
+
+static struct cpio_hdr_field cpio_newcx_header_info[] __initdata = {
+       NEWCX_FIELD(c_ino, &ino),
+       NEWCX_FIELD(c_mode, &mode_u32),
+       NEWCX_FIELD(c_uid, &uid),
+       NEWCX_FIELD(c_gid, &gid),
+       NEWCX_FIELD(c_nlink, &nlink),
+       NEWCX_FIELD(c_mtime, &mtime.tv_sec),
+       NEWCX_FIELD(c_mtime_nsec, &mtime.tv_nsec),
+       NEWCX_FIELD(c_filesize, &body_len),
+       NEWCX_FIELD(c_devmajor, &major),
+       NEWCX_FIELD(c_devminor, &minor),
+       NEWCX_FIELD(c_rdevmajor, &rmajor),
+       NEWCX_FIELD(c_rdevminor, &rminor),
+       NEWCX_FIELD(c_namesize, &name_len),
+       NEWCX_FIELD(c_xattrsize, &xattr_len),
+       { 0 },
+};
+
 static void __init parse_header(char *s)
 {
        char buf[CPIO_MAX_FIELD_SIZE + 1];
-       struct cpio_hdr_field *field = cpio_newc_header_info;
+       struct cpio_hdr_field *field = (cpio_format == CPIO_NEWC) ?
+               cpio_newc_header_info : cpio_newcx_header_info;
 
        while (field->size) {
                int ret = 0;
@@ -243,7 +286,12 @@ static void __init parse_header(char *s)
                        pr_err("invalid cpio header field (%d)", ret);
                field++;
        }
+
        mode = mode_u32;
+       if (cpio_format != CPIO_NEWCX) {
+               xattr_len = 0;
+               mtime.tv_nsec = 0;
+       }
 }
 
 /* FSM */
@@ -254,6 +302,7 @@ static int __init do_format(void);
 static int __init do_header(void);
 static int __init do_skip(void);
 static int __init do_name(void);
+static int __init do_xattrs(void);
 static int __init do_create(void);
 static int __init do_copy(void);
 static int __init do_symlink(void);
@@ -291,7 +340,7 @@ static void __init read_into(char *buf, unsigned size, 
fsm_state_t next)
        }
 }
 
-static __initdata char *header_buf, *symlink_buf, *name_buf;
+static __initdata char *header_buf, *symlink_buf, *name_buf, *xattr_buf;
 
 static int __init do_start(void)
 {
@@ -315,22 +364,34 @@ static int __init do_collect(void)
 
 static int __init do_format(void)
 {
-       if (memcmp(collected, "070707", CPIO_MAGIC_SIZE) == 0) {
+       int header_size = 0;
+
+       cpio_format = CPIO_NO_MAGIC;
+
+       if (!memcmp(collected, "070707", CPIO_MAGIC_SIZE)) {
                error("incorrect cpio method used: use -H newc option");
                return 1;
+       } else if (!memcmp(collected, "070701", CPIO_MAGIC_SIZE)) {
+               cpio_format = CPIO_NEWC;
+               header_size = sizeof(struct cpio_newc_header);
+       } else if (!memcmp(collected, "070703", CPIO_MAGIC_SIZE)) {
+               cpio_format = CPIO_NEWCX;
+               header_size = sizeof(struct cpio_newcx_header);
        }
-       if (memcmp(collected, "070701", CPIO_MAGIC_SIZE)) {
+
+       if (cpio_format == CPIO_NO_MAGIC) {
                error("no cpio magic");
                return 1;
        }
-       read_into(header_buf, sizeof(struct cpio_newc_header), do_header);
+       read_into(header_buf, header_size, do_header);
        return 0;
 }
 
 static int __init do_header(void)
 {
        parse_header(collected);
-       next_header = this_header + N_ALIGN(name_len) + body_len;
+       next_header = this_header + N_ALIGN(name_len) + X_ALIGN(xattr_len) +
+                     body_len;
        next_header = (next_header + 3) & ~3;
        state = do_skip;
        if (name_len <= 0 || name_len > PATH_MAX)
@@ -400,9 +461,17 @@ static int __init do_name(void)
        }
        memcpy_optional(name_buf, collected, N_ALIGN(name_len));
        state = do_create;
+       if (xattr_len > 0)
+               read_into(xattr_buf, X_ALIGN(xattr_len), do_xattrs);
        return 0;
 }
 
+static int __init do_xattrs(void)
+{
+       /* Do nothing for now */
+       state = do_create;
+       return 0;
+}
 
 static __initdata int wfd;
 
@@ -431,7 +500,7 @@ static int __init do_create(void)
                sys_mkdir(name_buf, mode);
                sys_chown(name_buf, uid, gid);
                sys_chmod(name_buf, mode);
-               dir_add(name_buf, mtime);
+               dir_add(name_buf, &mtime);
        } else if (S_ISBLK(mode) || S_ISCHR(mode) ||
                   S_ISFIFO(mode) || S_ISSOCK(mode)) {
                if (maybe_link(name_buf) == 0) {
@@ -439,7 +508,7 @@ static int __init do_create(void)
                        sys_mknod(name_buf, mode, rdev);
                        sys_chown(name_buf, uid, gid);
                        sys_chmod(name_buf, mode);
-                       do_utime(name_buf, mtime);
+                       do_utime(name_buf, &mtime);
                }
        } else if (S_ISLNK(mode)) {
                if (body_len > PATH_MAX)
@@ -455,7 +524,7 @@ static int __init do_copy(void)
                if (xwrite(wfd, victim, body_len) != body_len)
                        error("write error");
                sys_close(wfd);
-               do_utime(name_buf, mtime);
+               do_utime(name_buf, &mtime);
                eat(body_len);
                state = do_skip;
                return 0;
@@ -475,7 +544,7 @@ static int __init do_symlink(void)
        clean_path(name_buf, 0);
        sys_symlink(symlink_buf, name_buf);
        sys_lchown(name_buf, uid, gid);
-       do_utime(name_buf, mtime);
+       do_utime(name_buf, &mtime);
        state = do_skip;
        next_state = do_reset;
        return 0;
@@ -529,8 +598,9 @@ static char * __init unpack_to_rootfs(char *buf, unsigned 
long len)
        header_buf = kmalloc(CPIO_MAX_HEADER_SIZE, GFP_KERNEL);
        symlink_buf = kmalloc(PATH_MAX + 1, GFP_KERNEL);
        name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
+       xattr_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 
-       if (!header_buf || !symlink_buf || !name_buf)
+       if (!header_buf || !symlink_buf || !name_buf || !xattr_buf)
                panic("can't allocate buffers");
 
        state = do_start;
@@ -575,6 +645,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned 
long len)
                len -= my_inptr;
        }
        dir_utime();
+       kfree(xattr_buf);
        kfree(name_buf);
        kfree(symlink_buf);
        kfree(header_buf);
-- 
2.10.3.dirty

Reply via email to