[PREVIEW] [RFC PATCH 3/5] erofs-mkfs: support to build a image from the specfic root directory

bluce.liguifu at huawei.com bluce.liguifu at huawei.com
Fri Nov 16 14:30:18 AEDT 2018


From: Li Guifu <bluce.liguifu at huawei.com>

Currently, regular files, directories, special files defined in POSIX
are supported and the generated image can be mounted by kernel.

Signed-off-by: Li Guifu <bluce.liguifu at huawei.com>
Signed-off-by: Miao Xie <miaoxie at huawei.com>
Signed-off-by: Fang Wei <fangwei1 at huawei.com>
---
 erofs_cache.c | 211 ++++++++++++++
 erofs_cache.h |  58 ++++
 mkfs_erofs.h  |  36 ---
 mkfs_file.c   | 304 ++++++++++++++++++++
 mkfs_file.h   |  79 ++++++
 mkfs_inode.c  | 773 ++++++++++++++++++++++++++++++++++++++++++++++++++
 mkfs_inode.h  |  84 ++++++
 mkfs_main.c   |  28 ++
 8 files changed, 1537 insertions(+), 36 deletions(-)
 create mode 100644 erofs_cache.c
 create mode 100644 erofs_cache.h
 create mode 100644 mkfs_file.c
 create mode 100644 mkfs_file.h
 create mode 100644 mkfs_inode.c
 create mode 100644 mkfs_inode.h

diff --git a/erofs_cache.c b/erofs_cache.c
new file mode 100644
index 0000000..a2153fe
--- /dev/null
+++ b/erofs_cache.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs_cache.c
+ *
+ * Copyright (C) 2018 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Miao Xie <miaoxie at huawei.com>
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "erofs_fs.h"
+#include "erofs_types.h"
+#include "erofs_cache.h"
+#include "erofs_error.h"
+#include "erofs_debug.h"
+#include "erofs_io.h"
+
+#include "mkfs_erofs.h"
+#include "mkfs_inode.h"
+
+/* The 1st block is used for SUPER BLOCK, so skip it. */
+static u64 erofs_current_block = 1;
+static LIST_HEAD(erofs_global_blocks);
+static LIST_HEAD(erofs_free_blocks);
+static LIST_HEAD(erofs_full_blocks);
+
+static char* erofs_blk_buf;
+
+/*
+ * Note: Since we reserved the 1st block for super block, so we can reuse
+ * this block number as a special number, we use it to tell the caller that
+ * there is NO ENOUGH FREE SPACE!!!!
+ *
+ * So the result value:
+ * !0 : Allocate the blocks successfully, this is block number of
+ *      the 1st block.
+ * 0  : ENOSPC, There is no enough space.
+ */
+u32 erofs_alloc_blocks(u32 nblocks)
+{
+	u32 blkaddr;
+	u64 devlen;
+
+	assert(nblocks);
+
+	devlen = dev_length();
+	if (erofs_current_block > (u64)UINT32_MAX ||
+	    erofs_current_block + nblocks > ((u64)UINT32_MAX) + 1 ||
+	    (erofs_current_block + nblocks) << EROFS_BLOCKSIZE_BITS > devlen) {
+		erofs_err("There is no enough free space(curr: %llu, need: %u, device blocks: %llu).",
+			   (unsigned long long)erofs_current_block, nblocks,
+			   (unsigned long long)devlen >> EROFS_BLOCKSIZE_BITS);
+		return 0;
+	}
+
+	blkaddr = (u32)erofs_current_block;
+	erofs_current_block += nblocks;
+
+	return blkaddr;
+}
+
+u64 erofs_get_total_blocks(void)
+{
+	return erofs_current_block;
+}
+
+
+block_buffer_t* erofs_alloc_multi_block_buffer(u32 nblocks)
+{
+	block_buffer_t*     blk;
+	block_buffer_t*     next;
+	block_buffer_t*     first;
+	struct list_head    blocks;
+	u32 blkaddr;
+	u32 i;
+	int ret;
+
+	init_list_head(&blocks);
+
+	for (i = 0; i < nblocks; i++) {
+		blk = (block_buffer_t*)malloc(sizeof(block_buffer_t));
+		if (!blk) {
+			erofs_err("Fail to alloc memory for block buffer");
+			ret = -ENOMEM;
+			goto free_block_buffer;
+		}
+		memset(blk, 0, sizeof(block_buffer_t));
+		init_list_head(&blk->bb_metadata_list);
+
+		list_add_tail(&blk->bb_global_node, &blocks);
+	}
+
+	blkaddr = erofs_alloc_blocks(nblocks);
+	if (!blkaddr) {
+		ret = -ENOSPC;
+		goto free_block_buffer;
+	}
+
+	first = list_first_entry(&blocks, block_buffer_t, bb_global_node);
+	list_for_each_entry_safe(blk, next, &blocks, bb_global_node) {
+		blk->bb_blkaddr = blkaddr;
+		blkaddr++;
+
+		list_del(&blk->bb_global_node);
+		list_add_tail(&blk->bb_global_node, &erofs_global_blocks);
+		list_add_tail(&blk->bb_alloc_node, &erofs_free_blocks);
+	}
+
+	return first;
+
+free_block_buffer:
+	list_for_each_entry_safe(blk, next, &blocks, bb_global_node) {
+		list_del(&blk->bb_global_node);
+		free(blk);
+	}
+	return ERR_PTR(ret);
+}
+
+block_buffer_t* erofs_alloc_single_block_buffer(void)
+{
+	return erofs_alloc_multi_block_buffer(1);
+}
+
+block_buffer_t* erofs_look_up_free_pos(int request_size)
+{
+	block_buffer_t* blk = NULL;
+
+	list_for_each_entry(blk, &erofs_free_blocks, bb_alloc_node) {
+		if ((request_size + blk->bb_free_slot * EROFS_SLOTSIZE) <
+		     EROFS_BLKSIZE)
+			return blk;
+	}
+
+	blk = erofs_alloc_single_block_buffer();
+	return blk;
+}
+
+int erofs_flush_all_blocks(void)
+{
+	struct block_buffer* blk;
+	struct erofs_meta_node*  node;
+	struct erofs_node_info*  inode;
+	struct erofs_index_info* index;
+	char*            pbuf;
+	int         count;
+	int         ret = 0;
+
+	list_for_each_entry(blk, &erofs_global_blocks, bb_global_node) {
+		pbuf = erofs_blk_buf;
+		memset(pbuf, 0, EROFS_BLKSIZE);
+
+		list_for_each_entry(node, &blk->bb_metadata_list, m_node) {
+			switch (node->m_type) {
+			case EROFS_META_INODE:
+				inode = (struct erofs_node_info*)node;
+
+				count = erofs_write_inode_buffer(inode, pbuf);
+				break;
+			case EROFS_META_INDEX:
+				index = (struct erofs_index_info*)node;
+
+				count = erofs_write_index_buffer(index, pbuf);
+				break;
+			default:
+				erofs_err("Wrong metadata type");
+				assert(0);
+			}
+
+			count = round_up(count, EROFS_SLOTSIZE);
+			assert(count == node->m_len);
+			pbuf += count;
+		}
+
+		ret = dev_write(erofs_blk_buf, BLKNO_TO_ADDR(blk->bb_blkaddr),
+				EROFS_BLKSIZE);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+void erofs_put_block_buffer(struct block_buffer* blk)
+{
+	if (blk->bb_free_slot == MAX_NID_INDEX_PER_BLK) {
+		list_del(&blk->bb_alloc_node);
+		list_add_tail(&blk->bb_alloc_node, &erofs_full_blocks);
+	} else if (blk->bb_free_slot > MAX_NID_INDEX_PER_BLK) {
+		erofs_err("block buffer overflow: free_slot = %d, MAX_NID_INDEX_PER_BLK = %d",
+			  blk->bb_free_slot, MAX_NID_INDEX_PER_BLK);
+		assert(0);
+	}
+}
+
+int erofs_cache_init(u64 start_blk)
+{
+	erofs_blk_buf = malloc(EROFS_BLKSIZE);
+	if (!erofs_blk_buf)
+		return -ENOMEM;
+	erofs_current_block = start_blk;
+	return 0;
+}
+
+void erofs_cache_deinit(void)
+{
+	if (erofs_blk_buf)
+		free(erofs_blk_buf);
+}
diff --git a/erofs_cache.h b/erofs_cache.h
new file mode 100644
index 0000000..3945739
--- /dev/null
+++ b/erofs_cache.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs_cache.h
+ *
+ * Copyright (C) 2018 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Li Guifu <bluce.liguifu at huawei.com>
+ */
+#ifndef __EROFS_CACHE_H__
+#define __EROFS_CACHE_H__
+
+#include "list_head.h"
+
+enum erofs_meta_type {
+	EROFS_META_INODE,
+	EROFS_META_INDEX,
+	EROFS_META_MAX_TYPES,
+};
+
+struct erofs_meta_node {
+	struct list_head    m_node;
+	struct block_buffer* m_blk;
+	int         m_type;
+	int         m_slot;
+	int         m_len;
+};
+
+static inline void erofs_meta_node_init(struct erofs_meta_node* node, int type)
+{
+	init_list_head(&node->m_node);
+	node->m_type = type;
+	node->m_blk = NULL;
+	node->m_slot = 0;
+	node->m_len = 0;
+}
+
+typedef struct block_buffer {
+	/* These two members are used to block management. */
+	struct list_head    bb_global_node;
+	struct list_head    bb_alloc_node;
+
+	/* This is the head of all metadata which is hold in this block. */
+	struct list_head    bb_metadata_list;
+
+	u32         bb_blkaddr;
+	int         bb_free_slot;
+} block_buffer_t;
+
+block_buffer_t* erofs_alloc_single_block_buffer(void);
+block_buffer_t* erofs_alloc_multi_block_buffer(u32 nblocks);
+block_buffer_t* erofs_look_up_free_pos(int request_size);
+int erofs_flush_all_blocks(void);
+int erofs_cache_init(u64 start_blk);
+void erofs_cache_deinit(void);
+u32 erofs_alloc_blocks(u32 nblocks);
+void erofs_put_block_buffer(struct block_buffer* blk);
+u64 erofs_get_total_blocks(void);
+#endif
diff --git a/mkfs_erofs.h b/mkfs_erofs.h
index 1790862..e408474 100644
--- a/mkfs_erofs.h
+++ b/mkfs_erofs.h
@@ -44,40 +44,4 @@ typedef unsigned int __u32;
 #define MAX_NID_INDEX_PER_BLK   (EROFS_BLKSIZE / EROFS_SLOTSIZE)
 
 
-struct erofs_node_info {
-	/* Original member */
-	struct list_head list;
-	struct list_head subdir_head;/* sub dirs or files */
-	struct list_head xattr_head;
-
-	u64 inode_base_addr;         /* base address of a inode */
-	char name[NAME_MAX];         /* the name of current inode */
-	char fullpath[PATH_MAX + 1];
-	u16 d_nameoff;
-	u16         i_iver;          /* Inode Version */
-	u16         i_dmode;         /* Data mode */
-	u16         i_xattr_scnt;    /* Inline xattr space count */
-	u16         i_shared_count;
-	u16         i_mode;
-	u8          i_type;          /* Inode type: File, Dir...*/
-	u64         i_size;
-	union {
-		u32     i_blkaddr;
-		u32     i_blocks;
-		u32     i_rdev;
-	};
-	u32         i_ino;
-	u32         i_uid;
-	u32         i_gid;
-	u64         i_ctime;
-	u32         i_ctime_nsec;
-	u32         i_nlink;
-
-	/* If compress file, we use it store index info */
-	char*       i_inline_data;
-	int         i_inline_datalen;
-	int         i_inline_align_size;
-};
-
-
 #endif
diff --git a/mkfs_file.c b/mkfs_file.c
new file mode 100644
index 0000000..4ff2790
--- /dev/null
+++ b/mkfs_file.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * mkfs_file.c
+ *
+ * Copyright (C) 2018 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Li Guifu <bluce.liguifu at huawei.com>
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define _LARGEFILE64_SOURCE
+#include <assert.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/kdev_t.h>
+
+
+#ifndef O_BINARY
+#define O_BINARY    0
+#endif
+#include "erofs_types.h"
+#include "list_head.h"
+#include "erofs_fs.h"
+#include "erofs_cache.h"
+
+#define pr_fmt(fmt) "MKFS-FILE: "FUNC_LINE_FMT fmt"\n"
+#include "erofs_debug.h"
+
+#include "mkfs_erofs.h"
+#include "mkfs_file.h"
+#include "mkfs_inode.h"
+#include "erofs_io.h"
+
+
+#define DIRENT_MAX_NAME_LEN 256
+
+
+static u8 get_file_type(struct stat64* st)
+{
+	u8 file_type = EROFS_FT_MAX;
+
+	switch (st->st_mode & S_IFMT) {
+	case S_IFREG:
+		file_type = EROFS_FT_REG_FILE;
+		break;
+
+	case S_IFDIR:
+		file_type = EROFS_FT_DIR;
+		break;
+
+	case S_IFLNK:
+		file_type = EROFS_FT_SYMLINK;
+		break;
+
+	case S_IFCHR:
+		file_type = EROFS_FT_CHRDEV;
+		break;
+
+	case S_IFBLK:
+		file_type = EROFS_FT_BLKDEV;
+		break;
+
+	case S_IFIFO:
+		file_type = EROFS_FT_FIFO;
+		break;
+
+	case S_IFSOCK:
+		file_type = EROFS_FT_SOCK;
+		break;
+
+	default:
+		erofs_err("file type[0x%X]", st->st_mode & S_IFMT);
+		break;
+	}
+
+	return file_type;
+
+}
+
+static inline u32 new_encode_dev(dev_t dev)
+{
+	unsigned major = MAJOR(dev);
+	unsigned minor = MINOR(dev);
+	return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
+}
+
+
+struct erofs_node_info* erofs_init_inode(char* full_path_name)
+{
+	int ret;
+	struct stat64 st;
+	struct erofs_node_info* inode = NULL;
+	char* file_name = NULL;
+
+	file_name = strrchr(full_path_name, '/');
+	if(!file_name){
+		file_name = full_path_name;
+	}else{
+		file_name = file_name + 1;
+	}
+
+	inode = alloc_erofs_node();
+	if (!inode) {
+		erofs_err("inode is NULL, alloc failed");
+		goto Err_alloc;
+	}
+
+	ret = snprintf(inode->i_name, MAX_NAME, "%s", file_name);
+	if (ret < 0 || ret >= MAX_PATH) {
+		erofs_err("snprintf errorly file_name[%s] ret[%d]", file_name, ret);
+		goto Err_alloced;
+	}
+	ret = snprintf(inode->i_fullpath, MAX_PATH, "%s", full_path_name);
+	if (ret < 0 || ret >= MAX_PATH) {
+		erofs_err("snprintf errorly full_path_name[%s] ret[%d]",
+			  full_path_name, ret);
+		goto Err_alloced;
+	}
+
+	ret = lstat64(inode->i_fullpath, &st);
+	if (ret) {
+		erofs_err("stat failed path[%s]", inode->i_fullpath);
+		goto Err_alloced;
+	}
+
+	/* It is ugly code that is for old code everywhere */
+	inode->i_mode = st.st_mode;
+	inode->i_uid = st.st_uid;
+	inode->i_gid = st.st_gid;
+	inode->i_nlink = st.st_nlink;
+	inode->i_type = get_file_type(&st);
+
+	if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) ||
+	    S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
+		inode->i_rdev = new_encode_dev(st.st_rdev);
+		inode->i_size = 0;
+	} else {
+		inode->i_size = st.st_size;
+	}
+
+	return inode;
+
+
+Err_alloced:
+	free(inode);
+
+Err_alloc:
+	return NULL;
+}
+
+int erofs_create_files_list(struct erofs_node_info* inode)
+{
+	int  ret    = 0;
+	u64  d_size = 0;
+	DIR* dirp   = NULL;
+	char file_path[MAX_PATH + 1];
+	struct stat64 s;
+	struct dirent* dp;
+	struct list_head* pos;
+	struct erofs_node_info* dl;
+
+
+	if(!strncmp(inode->i_name, "lost+found", strlen("lost+found"))){
+		return 0;
+	}
+
+	if (0 == lstat64(inode->i_fullpath, &s)) {
+		if (S_ISREG(s.st_mode)) {
+			erofs_err("[%s] is a regular file", inode->i_fullpath);
+			ret = -ENOTDIR;
+			goto error;
+		}
+	} else {
+		erofs_err("stat failed [%s]", inode->i_fullpath);
+		ret = -ENOENT;
+		goto error;
+	}
+
+	dirp = opendir(inode->i_fullpath);
+	if (!dirp) {
+		erofs_info("dirp is NULL dir=%s errno=%s",
+			   inode->i_fullpath, strerror(errno));
+		ret = -errno;
+		goto error;
+	}
+
+	errno = 0;
+	while ((dp = readdir(dirp)) != NULL) {
+		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+			continue;
+
+		ret = snprintf(file_path, MAX_PATH, "%s/%s",
+			       inode->i_fullpath, dp->d_name);
+		if (ret < 0 || ret >= MAX_PATH) {
+			erofs_err("snprintf errorly ret[%d]", ret);
+			ret = -ENOMEM;
+			goto error;
+		}
+		dl = erofs_init_inode(file_path);
+		if(!dl){
+			erofs_err("init inode failed !!");
+			ret = -ENOENT;
+			goto error;
+		}
+
+		dl->i_iver = erofs_check_disk_inode_version(dl);
+		list_add_sort(&inode->i_subdir_head, dl);
+	}
+
+	if (errno != 0) {
+		erofs_err("inode[%s] error[%s]", inode->i_name, strerror(EBADF));
+		ret = -errno;
+		goto error;
+	}
+
+	list_for_each(pos, &inode->i_subdir_head) {
+		struct erofs_node_info* d = container_of(pos,
+							 struct erofs_node_info,
+							 i_list);
+		if (((d_size & (EROFS_BLKSIZE - 1)) +
+		     EROFS_DIRENT_SIZE +
+		     strlen(d->i_name)) > EROFS_BLKSIZE) {
+			d_size = round_up(d_size, EROFS_BLKSIZE);
+		}
+		d_size += EROFS_DIRENT_SIZE + strlen(d->i_name);
+	}
+	inode->i_size = d_size;
+
+	list_for_each(pos, &inode->i_subdir_head) {
+		struct erofs_node_info* d = container_of(pos,
+							 struct erofs_node_info,
+							 i_list);
+		if (d->i_type == EROFS_FT_DIR) {
+			ret = erofs_create_files_list(d);
+			if(ret < 0)
+				goto error;
+		}
+	}
+
+	closedir(dirp);
+	return 0;
+error:
+	return ret;
+}
+
+
+int list_add_sort(struct list_head* head, struct erofs_node_info* inode)
+{
+	struct list_head* pos;
+
+	if (list_empty(head)) {
+		list_add(&inode->i_list, head);
+		return 0;
+	}
+
+	list_for_each(pos, head) {
+		struct erofs_node_info* d = container_of(pos,
+							 struct erofs_node_info,
+							 i_list);
+
+		if (strcmp(d->i_name, inode->i_name) <= 0)
+			continue;
+
+		list_add_tail(&inode->i_list, &d->i_list);
+		return 0;
+	}
+
+	list_add_tail(&inode->i_list, head);
+	return 0;
+
+}
+
+struct erofs_node_info* alloc_erofs_node(void)
+{
+	struct erofs_node_info* f = calloc(sizeof(struct erofs_node_info), 1);
+
+	if (!f) {
+		erofs_err("calloc failed!!!");
+		return NULL;
+	}
+
+	f->i_inline_align_size = EROFS_INLINE_GENERIC_ALIGN_SIZE;
+	erofs_meta_node_init(&f->i_meta_node, EROFS_META_INODE);
+	init_list_head(&f->i_subdir_head);
+	init_list_head(&f->i_compr_idxs_list);
+	init_list_head(&f->i_xattr_head);
+
+	return f;
+}
\ No newline at end of file
diff --git a/mkfs_file.h b/mkfs_file.h
new file mode 100644
index 0000000..0d84773
--- /dev/null
+++ b/mkfs_file.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * mkfs_file.h
+ *
+ * Copyright (C) 2018 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Li Guifu <bluce.liguifu at huawei.com>
+ */
+#ifndef __MKFS_FILE_H
+#define __MKFS_FILE_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "list_head.h"
+#include "erofs_fs.h"
+
+#define FILE_TYPE_NONE      (0)
+#define FILE_TYPE_COMPR     (1)
+#define FILE_TYPE_MAX       (2)
+
+/*
+ * Some micros for generic compress index convertion:
+ * CIG: Compress Index Generic
+ * D0: Delta0
+ * D1: Delta1
+ * LO: low 4 bits
+ * HI: high 4 bits
+ */
+#define EROFS_CIG_D0_LO_MASK    (0xF)
+#define EROFS_CIG_D0_LO_SHL     (12)
+#define EROFS_CIG_D0_HI_MASK    (0xF0)
+#define EROFS_CIG_D0_HI_SHR     (0)
+#define EROFS_CIG_D1_SHIFT      (8)
+
+struct erofs_compr_idx {
+	u16 di_advise;
+	u16 di_clusterofs;
+	u16 delta[2];    /* [0] - relative index to the 1st block */
+	/* [1] - relative index to the last block */
+	u32 blkaddr;
+};
+
+/* cc_nidxs == -1 means it is a inlined compress data */
+#define EROFS_COMPR_CTX_INLINED_DATA    (-1)
+
+struct erofs_compr_ctx {
+	char*       cc_srcbuf;
+	char*       cc_dstbuf;
+	u64         cc_pos;
+	int         cc_buflen;
+	int         cc_srclen;
+	int         cc_dstlen;
+	struct erofs_compr_idx*  cc_idxs;
+	int         cc_nidxs;
+};
+
+struct erofs_compr_info {
+	struct erofs_compr_alg*  ci_alg;
+	int         ci_lvl;
+};
+
+struct erofs_node_info;
+
+struct erofs_node_info* alloc_erofs_node(void);
+struct erofs_node_info* erofs_init_inode(char* full_path_name);
+int list_add_sort(struct list_head* head, struct erofs_node_info* entry);
+void dump_inode(struct erofs_inode_v1* inode);
+int erofs_create_files_list(struct erofs_node_info* entry);
+u32 erofs_calc_inline_data_size(struct erofs_node_info* inode);
+int erofs_check_compressible(struct erofs_node_info* inode);
+int erofs_compress_file(struct erofs_node_info* inode);
+void erofs_dump_compr_radio(void);
+int erofs_init_compress_context(struct erofs_compr_ctx* ctx);
+void erofs_deinit_compress_context(struct erofs_compr_ctx* ctx);
+void erofs_reset_compress_context(struct erofs_compr_ctx* ctx);
+#endif
\ No newline at end of file
diff --git a/mkfs_inode.c b/mkfs_inode.c
new file mode 100644
index 0000000..e84fced
--- /dev/null
+++ b/mkfs_inode.c
@@ -0,0 +1,773 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * mkfs_inode.c
+ *
+ * Copyright (C) 2018 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Li Guifu <bluce.liguifu at huawei.com>
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <libgen.h>
+
+#include "erofs_fs.h"
+#include "erofs_cache.h"
+#include "erofs_error.h"
+#include "mkfs_erofs.h"
+#include "mkfs_file.h"
+#include "mkfs_inode.h"
+#include "erofs_io.h"
+
+
+#define pr_fmt(fmt) "MKFS_INODE: "FUNC_LINE_FMT fmt"\n"
+#include "erofs_debug.h"
+
+extern struct erofs_super_block* sb;
+
+u32 erofs_calc_inode_base_size(struct erofs_node_info* inode)
+{
+	u32 size;
+
+	if (inode->i_iver == EROFS_INODE_LAYOUT_V1)
+		size = EROFS_INODE_V1_SIZE;
+	else
+		size = EROFS_INODE_V2_SIZE;
+
+	return size;
+}
+
+u32 erofs_calc_inline_data_size(struct erofs_node_info* inode)
+{
+	u32 size =  erofs_calc_inode_base_size(inode);
+
+	if (size >= EROFS_BLKSIZE) {
+		return 0;
+	} else {
+		return (EROFS_BLKSIZE - size);
+	}
+}
+
+static inline u64 erofs_calc_compr_index_count(struct erofs_node_info* inode)
+{
+	return round_up(inode->i_size, EROFS_BLKSIZE) / EROFS_BLKSIZE;
+}
+
+u8 erofs_check_disk_inode_version(struct erofs_node_info* inode)
+{
+#if 1
+	(void)inode;
+	return EROFS_INODE_LAYOUT_V1;
+#else
+	/*
+	 * Check if the members of v0 inode structure can hold the data,
+	 * Check Item:
+	 * - i_size: 32bits vs 64 bits
+	 * - i_uid:  16bits vs 32bits
+	 * - i_gid:  16bits vs 32bits
+	 * - i_nlink:16bits vs 32bits
+	 * - i_ctime:If it is set or not
+	 */
+#endif
+}
+
+void mkfs_rank_inode(struct erofs_node_info* inode)
+{
+	block_buffer_t* blk;
+	block_buffer_t* next;
+	struct erofs_meta_node* node;
+	struct erofs_index_info* indexes;
+	u64 request_size;
+	u64 noninline_nidxs;
+	u64 first_idx;
+	u64 idx_nblks;
+	int nidxs;
+	int inline_size = 0;
+
+	node = &inode->i_meta_node;
+	request_size = erofs_calc_inode_base_size(inode);
+
+	request_size = round_up(request_size,
+				inode->i_inline_align_size);
+
+	if (EROFS_INODE_LAYOUT_INLINE == inode->i_dmode) {
+		inline_size = inode->i_size % EROFS_BLKSIZE;
+		/* we put inode into inline mode asasp */
+		if (inline_size + request_size > EROFS_BLKSIZE) {
+			erofs_err("inode[%s] inline data overflow  i_size=%u slots size=%d",
+				  inode->i_name, inode->i_dmode, inline_size);
+			assert(0);
+		}
+
+
+	} else if (EROFS_INODE_LAYOUT_COMPRESSION == inode->i_dmode) {
+		inline_size += inode->i_inline_datalen;
+
+		/* we put inode into inline mode asasp */
+		if (inline_size + request_size > EROFS_BLKSIZE) {
+			erofs_err("inode[%s] inline data overflow  i_size=%"PRIu64" slots size=%d",
+				  inode->i_name, inode->i_size, inline_size);
+			assert(0);
+		}
+	}
+	request_size += inline_size;
+
+	/*
+	 * If no compress indexes or all indexes are inlined, noninline_nidxs
+	 * should be zero.
+	 */
+	noninline_nidxs = inode->i_compr_nidxs - inode->i_compr_inlined_nidxs;
+	idx_nblks = noninline_nidxs * EROFS_DECOMPR_IDX_SZ;
+	idx_nblks = round_up(idx_nblks, EROFS_BLKSIZE) / EROFS_BLKSIZE;
+
+	if (idx_nblks) {
+		assert(request_size == EROFS_BLKSIZE);
+
+		blk = erofs_alloc_multi_block_buffer(idx_nblks + 1);
+	} else {
+		blk = erofs_look_up_free_pos(request_size);
+	}
+
+	if (IS_ERR(blk))
+		assert(0);
+
+	node->m_blk = blk;
+	node->m_slot = blk->bb_free_slot;
+	node->m_len = round_up(request_size, EROFS_SLOTSIZE);
+	list_add_tail(&node->m_node, &blk->bb_metadata_list);
+	inode->i_base_addr = BLKNO_TO_ADDR(blk->bb_blkaddr) +
+					       blk->bb_free_slot * EROFS_SLOTSIZE;
+	blk->bb_free_slot += node->m_len / EROFS_SLOTSIZE;
+	next = list_next_entry(blk, bb_global_node);
+	erofs_put_block_buffer(blk);
+	blk = next;
+	first_idx = inode->i_compr_inlined_nidxs;
+
+	while (noninline_nidxs) {
+		if (noninline_nidxs >= EROFS_DECOMPR_IDXS_PER_BLK) {
+			nidxs = EROFS_DECOMPR_IDXS_PER_BLK;
+			request_size = EROFS_BLKSIZE;
+		} else {
+			nidxs = noninline_nidxs;
+			request_size = nidxs * EROFS_DECOMPR_IDX_SZ;
+			request_size = round_up(request_size, EROFS_SLOTSIZE);
+		}
+
+		indexes = malloc(sizeof(*indexes) + request_size);
+		if (!indexes) {
+			erofs_err("Failed to alloc memory for index info structure");
+			exit(EXIT_FAILURE);
+		}
+
+		erofs_meta_node_init(&indexes->i_meta_node, EROFS_META_INDEX);
+		indexes->i_1st_idx = first_idx;
+		indexes->i_nidxs = nidxs;
+		memset(indexes->i_idxs, 0, request_size);
+		list_add_tail(&indexes->i_node, &inode->i_compr_idxs_list);
+
+		node = &indexes->i_meta_node;
+		node->m_blk = blk;
+		node->m_type = EROFS_META_INDEX;
+
+		node->m_slot = blk->bb_free_slot;
+		blk->bb_free_slot += request_size / EROFS_SLOTSIZE;
+
+		node->m_len = request_size;
+		list_add_tail(&node->m_node, &blk->bb_metadata_list);
+
+		noninline_nidxs -= nidxs;
+		first_idx += nidxs;
+
+		next = list_next_entry(blk, bb_global_node);
+		erofs_put_block_buffer(blk);
+		blk = next;
+	}
+}
+
+struct erofs_node_info* mkfs_prepare_root_inode(char* root)
+{
+	if(!root)
+		return NULL;
+	return erofs_init_inode(root);
+}
+
+void mkfs_relocate_sub_inodes(struct erofs_node_info* inode)
+{
+	u32 blkaddr;
+	u32 nblocks;
+	u32 unaligned;
+	struct erofs_node_info* d = inode;
+
+	switch (d->i_type) {
+	case EROFS_FT_REG_FILE:
+	case EROFS_FT_DIR:
+	case EROFS_FT_SYMLINK:
+		unaligned = d->i_size % EROFS_BLKSIZE;
+		nblocks = d->i_size / EROFS_BLKSIZE;
+
+		if (unaligned > erofs_calc_inline_data_size(d)||
+		    (unaligned == 0 && nblocks != 0)) {
+			d->i_dmode = EROFS_INODE_LAYOUT_PLAIN;
+			mkfs_rank_inode(d);
+
+			if (unaligned != 0)
+				nblocks++;
+			blkaddr = erofs_alloc_blocks(nblocks);
+			if (!blkaddr)
+				exit(EXIT_FAILURE);
+
+			d->i_blkaddr = blkaddr;
+		} else {
+			d->i_dmode = EROFS_INODE_LAYOUT_INLINE;
+			d->i_inline_datalen = unaligned;
+			mkfs_rank_inode(d);
+
+			if (nblocks > 0) {
+				blkaddr = erofs_alloc_blocks(nblocks);
+				if (!blkaddr)
+					exit(EXIT_FAILURE);
+
+				d->i_blkaddr = blkaddr;
+			} else {
+				d->i_blkaddr = 0;
+			}
+		}
+		break;
+	case EROFS_FT_BLKDEV:
+	case EROFS_FT_CHRDEV:
+	case EROFS_FT_FIFO:
+	case EROFS_FT_SOCK:
+		mkfs_rank_inode(d);
+		break;
+
+	default:
+		erofs_err("inode[%s] file_type error =%d",
+			  d->i_fullpath, d->i_type);
+		exit(EXIT_FAILURE);
+	}
+
+	list_for_each_entry(d, &inode->i_subdir_head, i_list) {
+		mkfs_relocate_sub_inodes(d);
+	}
+}
+
+static u32 write_dirents(char* buf, u32 sum,
+			 struct list_head* start,
+			 struct list_head* end)
+{
+	char* pbuf = buf;
+	u32 size   = 0;
+	u32 base_nameoff = 0;
+	struct erofs_dirent dirent;
+	struct list_head* start_tmp = NULL;
+
+
+	base_nameoff = sum * EROFS_DIRENT_SIZE;
+	start_tmp = start;
+	while (start_tmp != end) {
+		struct erofs_node_info* d = container_of(start_tmp,
+							 struct erofs_node_info,
+							 i_list);
+		u32 name_len = strlen(d->i_name);
+
+		d->i_nameoff = base_nameoff;
+		memcpy(pbuf + base_nameoff, d->i_name, name_len);
+		base_nameoff += name_len;
+		start_tmp = start_tmp->next;
+	}
+
+	start_tmp = start;
+	while (start_tmp != end) {
+		struct erofs_node_info* d = container_of(start_tmp,
+							 struct erofs_node_info,
+							 i_list);
+		memset(&dirent, 0, EROFS_DIRENT_SIZE);
+
+		dirent.nid       = cpu_to_le64(mkfs_addr_to_nid(d->i_base_addr));
+		dirent.file_type = d->i_type;
+		dirent.nameoff   = cpu_to_le16(d->i_nameoff);
+		memcpy(pbuf + size, &dirent, EROFS_DIRENT_SIZE);
+		size += EROFS_DIRENT_SIZE;
+		start_tmp = start_tmp->next;
+	}
+	assert(base_nameoff <= EROFS_BLKSIZE);
+
+	return base_nameoff;
+}
+static void mkfs_write_inode_dir(struct erofs_node_info* inode)
+{
+	struct list_head* pos;
+	struct list_head* start;
+	u32 sum          = 0;
+	u32 blk_cnt      = 0;
+	u32 dentrys_size = 0;
+	char* pbuf       = NULL;
+	int ret          = 0;
+
+
+	/* dentrys were at inline area */
+	if (inode->i_dmode == EROFS_INODE_LAYOUT_INLINE) {
+		start = (&inode->i_subdir_head)->next;
+		/* dentry begin from the next block offset to inode,
+		 * so page_num should be 1
+		 */
+		pbuf = calloc(EROFS_BLKSIZE, 1);
+
+		if (!pbuf) {
+			erofs_err("calloc inode[%s] error[%s]",
+				inode->i_fullpath, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		list_for_each(pos, &inode->i_subdir_head) {
+			struct erofs_node_info* d = container_of(pos,
+								 struct erofs_node_info,
+								 i_list);
+			u32 len = strlen(d->i_name);
+
+			if ((dentrys_size + EROFS_DIRENT_SIZE + len) > EROFS_BLKSIZE) {
+				memset(pbuf, 0, EROFS_BLKSIZE);
+				write_dirents(pbuf, sum, start, pos);
+				ret = dev_write(pbuf,
+						BLKNO_TO_ADDR(inode->i_blkaddr + blk_cnt),
+						EROFS_BLKSIZE);
+				if (ret < 0) {
+					erofs_err("dev_write inode[%s] error[%s]",
+						  inode->i_fullpath, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+
+				blk_cnt += 1;
+				sum = 0;
+				dentrys_size = 0;
+				start = pos;
+			}
+
+			dentrys_size += EROFS_DIRENT_SIZE + len;
+			sum += 1;
+
+		}
+
+		/* write last page names */
+		if (start != pos) {
+			memset(pbuf, 0, EROFS_BLKSIZE);
+			inode->i_inline_data    = pbuf;
+			inode->i_inline_datalen = write_dirents(pbuf, sum, start, pos);
+		}
+
+	} else if (inode->i_dmode == EROFS_INODE_LAYOUT_PLAIN) {
+		start = (&inode->i_subdir_head)->next;
+		/* dentry begin from the next block offset to inode,
+		 * so page_num should be 1
+		 */
+		pbuf = calloc(EROFS_BLKSIZE, 1);
+		if (!pbuf) {
+			perror("calloc");
+			exit(EXIT_FAILURE);
+		}
+
+		list_for_each(pos, &inode->i_subdir_head) {
+			struct erofs_node_info* d = container_of(pos,
+								 struct erofs_node_info,
+								 i_list);
+			u32 len = strlen(d->i_name);
+
+			if ((dentrys_size + EROFS_DIRENT_SIZE + len) > EROFS_BLKSIZE) {
+				memset(pbuf, 0, EROFS_BLKSIZE);
+				write_dirents(pbuf, sum, start, pos);
+				dev_write(pbuf,
+					  BLKNO_TO_ADDR(inode->i_blkaddr + blk_cnt),
+					  EROFS_BLKSIZE);
+				if (ret < 0) {
+					erofs_err("dev_write inode[%s] error[%s]",
+						  inode->i_fullpath, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+
+				blk_cnt += 1;
+				sum = 0;
+				dentrys_size = 0;
+				start = pos;
+			}
+
+			dentrys_size += EROFS_DIRENT_SIZE + len;
+			sum += 1;
+
+		}
+
+		/* write last page names */
+		if (start != pos) {
+			memset(pbuf, 0, EROFS_BLKSIZE);
+			write_dirents(pbuf, sum, start, pos);
+			ret = dev_write(pbuf,
+					BLKNO_TO_ADDR(inode->i_blkaddr + blk_cnt),
+					EROFS_BLKSIZE);
+			if (ret < 0) {
+				erofs_err("dev_write inode[%s] error[%s]",
+					  inode->i_fullpath, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		free(pbuf);
+
+	} else {
+		erofs_err("inode->i_dmode[%u]mode 1 is not support right now",
+			  inode->i_dmode);
+		exit(EXIT_FAILURE);
+	}
+}
+
+
+static void mkfs_write_inode_regfile(struct erofs_node_info* inode)
+{
+	char* pbuf     = NULL;
+	int ret        = 0;
+	u32 i          = 0;
+	int fd         = 0;
+	u32 nblocks    = 0;
+	int unaligned  = 0;
+	u32 page_cnt   = inode->i_size / EROFS_BLKSIZE;
+	char* filepath = inode->i_fullpath;
+
+	fd = open(filepath, O_RDONLY);
+	if (fd < 0) {
+		perror("fopen() failed");
+		erofs_err("current path=%s", getcwd(NULL, 0));
+		exit(EXIT_FAILURE);
+	}
+
+	switch (inode->i_dmode) {
+	case EROFS_INODE_LAYOUT_PLAIN:
+
+		if ((inode->i_size % EROFS_BLKSIZE) != 0)
+			page_cnt += 1;
+
+		pbuf = calloc(EROFS_BLKSIZE, 1);
+		if (!pbuf) {
+			erofs_err("calloc inode[%s] error[%s]",
+				  inode->i_fullpath, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		for (i = 0; i < page_cnt; i++) {
+			memset(pbuf, 0, EROFS_BLKSIZE);
+			ret = read(fd, pbuf, EROFS_BLKSIZE);
+			if (ret < 0) {
+				erofs_err("read inode[%s] error[%s]",
+					  filepath, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+
+			ret = dev_write(pbuf,
+					BLKNO_TO_ADDR(inode->i_blkaddr + i),
+					EROFS_BLKSIZE);
+			if (ret < 0) {
+				erofs_err("dev_write inode[%s] ret[%d]", filepath, ret);
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		free(pbuf);
+		break;
+
+	case EROFS_INODE_LAYOUT_COMPRESSION:
+		/* it isn't supported right now */
+		assert(0);
+
+	case EROFS_INODE_LAYOUT_INLINE:
+		if (inode->i_size == 0)
+			break;
+
+		nblocks = inode->i_size / EROFS_BLKSIZE;
+		unaligned = inode->i_size % EROFS_BLKSIZE;
+		if (nblocks > 0) {
+			assert(inode->i_blkaddr != 0);
+
+			pbuf = calloc(EROFS_BLKSIZE, 1);
+			if (!pbuf) {
+				erofs_err("calloc inode[%s] error[%s]",
+					  inode->i_fullpath, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+
+			for (i = 0; i < nblocks; i++) {
+				memset(pbuf, 0, EROFS_BLKSIZE);
+				ret = read(fd, pbuf, EROFS_BLKSIZE);
+				if (ret < 0) {
+					erofs_err("read inode[%s] error[%s]",
+						  filepath, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+				ret = dev_write(pbuf,
+						BLKNO_TO_ADDR(inode->i_blkaddr + i),
+						EROFS_BLKSIZE);
+				if (ret < 0) {
+					erofs_err("dev_write inode[%s] ret[%d]", filepath, ret);
+					exit(EXIT_FAILURE);
+				}
+			}
+
+			free(pbuf);
+		}
+
+		if (unaligned > 0) {
+			inode->i_inline_data = calloc(EROFS_BLKSIZE, 1);
+			if (!inode->i_inline_data) {
+				erofs_err("calloc inode[%s] error[%s]",
+					  filepath, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			(void)lseek(fd, nblocks * EROFS_BLKSIZE, SEEK_SET);
+			inode->i_inline_datalen = read(fd,
+						       inode->i_inline_data,
+						       unaligned);
+			if (inode->i_inline_datalen < 0) {
+				erofs_err("read inode[%s] error[%s]",
+					  filepath, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		break;
+
+	default:
+		erofs_err("Inode[%s] mode error [%d]", filepath, inode->i_dmode);
+		exit(EXIT_FAILURE);
+		break;
+	}
+
+	close(fd);
+
+}
+
+static void mkfs_write_inode_symfile(struct erofs_node_info* inode)
+{
+	char* pbuf = NULL;
+	int   ret  = 0;
+
+	switch (inode->i_dmode) {
+	case EROFS_INODE_LAYOUT_PLAIN:
+		pbuf = calloc(EROFS_BLKSIZE, 1);
+		if (!pbuf) {
+			erofs_err("calloc inode[%s] error[%s]",
+				  inode->i_fullpath, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		ret = readlink(inode->i_fullpath, pbuf, inode->i_size);
+		if (ret < 0) {
+			erofs_err("readlink inode[%s] error[%s]",
+				  inode->i_fullpath, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		ret = dev_write(pbuf,
+				BLKNO_TO_ADDR(inode->i_blkaddr),
+				EROFS_BLKSIZE);
+		if (ret < 0) {
+			erofs_err("dev_write inode[%s] error[%s]",
+				  inode->i_fullpath, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+		free(pbuf);
+		break;
+
+	case EROFS_INODE_LAYOUT_COMPRESSION:
+		break;
+
+	case EROFS_INODE_LAYOUT_INLINE:
+		if (inode->i_size == 0)
+			break;
+
+		inode->i_inline_data = calloc(EROFS_BLKSIZE, 1);
+		if (!inode->i_inline_data) {
+			perror("calloc");
+			erofs_info("data_buf is NULL");
+			exit(EXIT_FAILURE);
+		}
+
+		inode->i_inline_datalen = readlink(inode->i_fullpath,
+						   inode->i_inline_data,
+						   inode->i_size);
+		if (inode->i_inline_datalen < 0) {
+			perror("readlink");
+			exit(EXIT_FAILURE);
+		}
+
+		break;
+
+	default:
+		erofs_err("Inode mode error [%d]", inode->i_dmode);
+		exit(EXIT_FAILURE);
+		break;
+	}
+
+}
+
+void mkfs_do_write_inodes_data(struct erofs_node_info* inode)
+{
+	struct list_head* pos;
+
+	switch (inode->i_type) {
+	case EROFS_FT_DIR:
+		mkfs_write_inode_dir(inode);
+		break;
+
+	case EROFS_FT_REG_FILE:
+		mkfs_write_inode_regfile(inode);
+		break;
+
+	case EROFS_FT_SYMLINK:
+		mkfs_write_inode_symfile(inode);
+		break;
+
+	default:
+		/* special devices file eg. chr block pipe sock */
+		break;
+	}
+
+	if (!list_empty(&inode->i_subdir_head)) {
+		list_for_each(pos, &inode->i_subdir_head) {
+			struct erofs_node_info* d = container_of(pos,
+								 struct erofs_node_info,
+								 i_list);
+			mkfs_do_write_inodes_data(d);
+		}
+	}
+
+}
+
+static int erofs_do_write_inode_buffer(struct erofs_node_info* inode,
+				       char* buf)
+{
+	struct erofs_inode_v1* v1;
+	struct erofs_inode_v2* v2;
+
+	if (inode->i_iver == EROFS_INODE_LAYOUT_V1) {
+		v1 = (struct erofs_inode_v1*)buf;
+		v1->i_advise = cpu_to_le16(inode->i_iver|(inode->i_dmode<<1));
+		v1->i_xattr_icount = cpu_to_le16(inode->i_xattr_scnt);
+		v1->i_mode = cpu_to_le16(inode->i_mode);
+		v1->i_nlink = cpu_to_le16((u16)inode->i_nlink);
+		v1->i_size = cpu_to_le32((u32)inode->i_size);
+		v1->i_ino = cpu_to_le32(inode->i_ino);
+		v1->i_uid = cpu_to_le16((u16)inode->i_uid);
+		v1->i_gid = cpu_to_le16((u16)inode->i_gid);
+
+		switch (inode->i_type) {
+		case EROFS_FT_CHRDEV:
+		case EROFS_FT_BLKDEV:
+		case EROFS_FT_FIFO:
+		case EROFS_FT_SOCK:
+			v1->i_u.rdev = cpu_to_le32(inode->i_rdev);
+			break;
+
+		default:
+			if (inode->i_dmode == EROFS_INODE_LAYOUT_COMPRESSION)
+				v1->i_u.compressed_blocks =
+					cpu_to_le32(inode->i_blocks);
+			else
+				v1->i_u.raw_blkaddr =
+					cpu_to_le32(inode->i_blkaddr);
+
+			break;
+		}
+
+		v1->i_checksum = 0;
+		return EROFS_INODE_V1_SIZE;
+	} else {
+		v2 = (struct erofs_inode_v2*)buf;
+		v2->i_advise = cpu_to_le16(inode->i_iver|(inode->i_dmode<<1));
+		v2->i_xattr_icount = cpu_to_le16(inode->i_xattr_scnt);
+		v2->i_mode = cpu_to_le16(inode->i_mode);
+		v2->i_size = cpu_to_le64(inode->i_size);
+		v2->i_u.raw_blkaddr = cpu_to_le32(inode->i_blkaddr);
+		v2->i_ino = cpu_to_le32(inode->i_ino);
+		v2->i_uid = cpu_to_le32(inode->i_uid);
+		v2->i_gid = cpu_to_le32(inode->i_gid);
+		v2->i_ctime = cpu_to_le64(inode->i_ctime);
+		v2->i_ctime_nsec = cpu_to_le32(inode->i_ctime_nsec);
+		v2->i_nlink = cpu_to_le32(inode->i_nlink);
+
+		switch (inode->i_type) {
+		case EROFS_FT_CHRDEV:
+		case EROFS_FT_BLKDEV:
+		case EROFS_FT_FIFO:
+		case EROFS_FT_SOCK:
+			v2->i_u.rdev = cpu_to_le32(inode->i_rdev);
+			break;
+
+		default:
+			if (inode->i_dmode == EROFS_INODE_LAYOUT_COMPRESSION)
+				v2->i_u.compressed_blocks =
+					cpu_to_le32(inode->i_blocks);
+			else
+				v2->i_u.raw_blkaddr =
+					cpu_to_le32(inode->i_blkaddr);
+
+			break;
+		}
+
+		v2->i_checksum = 0;
+		return EROFS_INODE_V2_SIZE;
+	}
+}
+
+int erofs_write_inode_buffer(struct erofs_node_info* inode, char* buf)
+{
+	char* pbuf = buf;
+	int count = 0;
+
+	count += erofs_do_write_inode_buffer(inode, pbuf + count);
+
+	switch (inode->i_dmode) {
+	case EROFS_INODE_LAYOUT_COMPRESSION:    /* Compress File */
+	case EROFS_INODE_LAYOUT_INLINE:         /* Inline softlink or dir or file */
+		count = round_up(count, inode->i_inline_align_size);
+		if (inode->i_size > 0) {
+			memcpy(pbuf + count,
+			       inode->i_inline_data,
+			       inode->i_inline_datalen);
+			count += inode->i_inline_datalen;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	count = SLOT_ALIGN(count);
+	return count;
+}
+
+int erofs_write_index_buffer(struct erofs_index_info* index, char* buf)
+{
+	int count;
+
+	assert(index->i_nidxs);
+
+	count = index->i_nidxs * EROFS_DECOMPR_IDX_SZ;
+	memcpy(buf, index->i_idxs, count);
+
+	return count;
+}
+
+u64 mkfs_addr_to_nid(u64 addr)
+{
+	if (!IS_SLOT_ALIGN(addr)) {
+		erofs_err("SLOT NOT ALIGN: addr=0x%08"PRIX64"", addr);
+		exit(EXIT_FAILURE);
+	}
+	return (u64)((addr - (u64)sb->meta_blkaddr * EROFS_BLKSIZE) / 32);
+}
diff --git a/mkfs_inode.h b/mkfs_inode.h
new file mode 100644
index 0000000..a5c280a
--- /dev/null
+++ b/mkfs_inode.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs_inode.h
+ *
+ * Copyright (C) 2018 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Li Guifu <bluce.liguifu at huawei.com>
+ */
+#ifndef CONFIG_EROFS_MKFS_INODE_H
+#define CONFIG_EROFS_MKFS_INODE_H
+
+#include "list_head.h"
+#include "erofs_cache.h"
+#include "mkfs_file.h"
+
+#define MAX_PATH 4096
+#define MAX_NAME 256
+
+
+struct erofs_index_info {
+	/* Link to its block buffer */
+	struct erofs_meta_node i_meta_node;
+
+	/* Link to its inode */
+	struct list_head       i_node;
+
+	u64  i_1st_idx;
+	s32  i_nidxs;
+	struct z_erofs_vle_decompressed_index i_idxs[0];
+};
+
+struct erofs_node_info {
+	struct erofs_meta_node  i_meta_node;
+
+	/* Original member */
+	struct list_head i_list;
+	struct list_head i_subdir_head;         /* sub dirs or files */
+	struct list_head i_xattr_head;
+
+	u64         i_base_addr;              /* base address of a inode */
+	char        i_name[MAX_NAME];         /* the name of current inode */
+	char        i_fullpath[MAX_PATH + 1];
+	u16         i_nameoff;
+	u16         i_iver;          /* Inode Version */
+	u16         i_dmode;         /* Data mode */
+	u16         i_xattr_scnt;    /* Inline xattr space count */
+	u16         i_shared_count;
+	u16         i_mode;
+	u8          i_type;          /* Inode type: File, Dir...*/
+	u64         i_size;
+	union {
+		u32     i_blkaddr;
+		u32     i_blocks;
+		u32     i_rdev;
+	};
+	u32         i_ino;
+	u32         i_uid;
+	u32         i_gid;
+	u64         i_ctime;
+	u32         i_ctime_nsec;
+	u32         i_nlink;
+
+	/* If compress file, we use it store index info */
+	char*       i_inline_data;
+	s32         i_inline_datalen;
+	s32         i_inline_align_size;
+
+	struct erofs_compr_info i_compressor;
+	struct erofs_compr_ctx  i_compr_ctx;
+	u64         i_compr_nidxs;
+	u32         i_compr_inlined_nidxs;
+	struct list_head    i_compr_idxs_list;
+	struct erofs_index_info* i_compr_cur_index_info;
+};
+
+struct erofs_node_info* mkfs_prepare_root_inode(char* root);
+void mkfs_relocate_sub_inodes(struct erofs_node_info* droot);
+void mkfs_do_write_inodes_data(struct erofs_node_info* droot);
+u64 mkfs_addr_to_nid(u64 addr);
+int erofs_write_inode_buffer(struct erofs_node_info* inode, char* buf);
+int erofs_write_index_buffer(struct erofs_index_info* index, char* buf);
+u8 erofs_check_disk_inode_version(struct erofs_node_info* inode);
+
+#endif
diff --git a/mkfs_main.c b/mkfs_main.c
index d4ac161..69c88dc 100644
--- a/mkfs_main.c
+++ b/mkfs_main.c
@@ -18,6 +18,7 @@
 #include "erofs_fs.h"
 #include "mkfs_erofs.h"
 #include "erofs_io.h"
+#include "mkfs_inode.h"
 #define pr_fmt(fmt) "MKFS: "FUNC_LINE_FMT fmt"\n"
 #include "erofs_debug.h"
 
@@ -132,6 +133,8 @@ void mkfs_update_erofs_header(u64 root_addr)
 	}
 
 	sb->meta_blkaddr = cpu_to_le32(ADDR_TO_BLKNO(size));
+	sb->blocks   = cpu_to_le32(erofs_get_total_blocks());
+	sb->root_nid = cpu_to_le16(mkfs_addr_to_nid(root_addr));
 
 	sb_buf = calloc(size, 1);
 	if (!sb_buf) {
@@ -157,12 +160,37 @@ int main(int argc, char** argv)
 	mkfs_init_configure();
 	mkfs_parse_options_cfg(argc, argv);
 
+	proot_node = mkfs_prepare_root_inode(erofs_cfg.c_src_path);
+	if(!proot_node)
+		goto exit;
+	err = erofs_create_files_list(proot_node);
+	if(err)
+		goto exit;
+
+	err = erofs_cache_init(ADDR_TO_BLKNO(BLK_ALIGN(EROFS_HEADER_SIZE)));
+	if (err)
+		goto exit;
+
+	mkfs_relocate_sub_inodes(proot_node);
+
+	mkfs_do_write_inodes_data(proot_node);
+
+	err = erofs_flush_all_blocks();
+	if (err)
+		goto exit;
+
 	mkfs_update_erofs_header(proot_node->i_base_addr);
 
 	dev_close();
 	mkfs_free_config();
 	erofs_info("done");
 
+exit:
+
+	if (err)
+		erofs_err("\tError: Could not format the device!!!\n");
+
+	erofs_cache_deinit();
 	return err;
 }
 
-- 
2.17.1



More information about the Linux-erofs mailing list