[PREVIEW] [PATCH 3/5] erofs-mkfs: support to build a image from the specific root directory
Li Guifu
bluce.liguifu at huawei.com
Wed Dec 12 01:27:19 AEDT 2018
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 | 207 ++++++++++++
erofs_cache.h | 58 ++++
mkfs_file.c | 290 +++++++++++++++++
mkfs_file.h | 79 +++++
mkfs_inode.c | 852 ++++++++++++++++++++++++++++++++++++++++++++++++++
mkfs_inode.h | 83 +++++
mkfs_main.c | 31 +-
7 files changed, 1599 insertions(+), 1 deletion(-)
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..5b80592
--- /dev/null
+++ b/erofs_cache.c
@@ -0,0 +1,207 @@
+// 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_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);
+
+/*
+ * 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 *erofs_blk_buf;
+ char *pbuf;
+ int count;
+ int ret;
+ u32 addr;
+
+ erofs_blk_buf = malloc(EROFS_BLKSIZE);
+ if (!erofs_blk_buf)
+ return -ENOMEM;
+
+ 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;
+ }
+
+ addr = blk->bb_blkaddr;
+
+ ret = dev_write(
+ erofs_blk_buf, BLKNO_TO_ADDR(addr), EROFS_BLKSIZE);
+ if (ret)
+ break;
+ }
+
+ free(erofs_blk_buf);
+
+ 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_current_block = start_blk;
+ return 0;
+}
diff --git a/erofs_cache.h b/erofs_cache.h
new file mode 100644
index 0000000..ca0702a
--- /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 "mkfs_erofs.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_file.c b/mkfs_file.c
new file mode 100644
index 0000000..a7be11f
--- /dev/null
+++ b/mkfs_file.c
@@ -0,0 +1,290 @@
+// 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 <inttypes.h>
+#include <sys/types.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_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 int major = MAJOR(dev);
+ unsigned int 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 (lstat64(inode->i_fullpath, &s) == 0) {
+ 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;
+}
diff --git a/mkfs_file.h b/mkfs_file.h
new file mode 100644
index 0000000..3b23d00
--- /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 "mkfs_erofs.h"
+
+#define FILE_TYPE_NONE (0)
+#define FILE_TYPE_COMPR (1)
+#define FILE_TYPE_MAX (2)
+
+/*
+ * Some micros for generic compress index conversion:
+ * 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
diff --git a/mkfs_inode.c b/mkfs_inode.c
new file mode 100644
index 0000000..7271ab6
--- /dev/null
+++ b/mkfs_inode.c
@@ -0,0 +1,852 @@
+// 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_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;
+}
+
+static int erofs_calc_inline_compr_index_count(struct erofs_node_info *inode)
+{
+ int size;
+
+ size = erofs_calc_inode_base_size(inode);
+ size = round_up(size, EROFS_INLINE_INDEX_ALIGN_SIZE);
+ size += sizeof(struct erofs_extent_header);
+
+ assert(size < EROFS_BLKSIZE);
+
+ size = EROFS_BLKSIZE - size;
+
+ assert(size % EROFS_DECOMPR_IDX_SZ == 0);
+
+ return size / EROFS_DECOMPR_IDX_SZ;
+}
+
+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
+}
+
+static void erofs_init_compress_inode(struct erofs_node_info *inode)
+{
+ int inlined_nidxs;
+
+ inode->i_dmode = EROFS_INODE_LAYOUT_COMPRESSION;
+
+ if (inode->i_compr_ctx.cc_nidxs == EROFS_COMPR_CTX_INLINED_DATA) {
+ inode->i_inline_datalen = inode->i_compr_ctx.cc_dstlen;
+ return;
+ }
+
+ inode->i_compr_nidxs = erofs_calc_compr_index_count(inode);
+
+ inlined_nidxs = erofs_calc_inline_compr_index_count(inode);
+
+ if (inode->i_compr_nidxs > (u64)inlined_nidxs)
+ inode->i_compr_inlined_nidxs = inlined_nidxs;
+ else
+ inode->i_compr_inlined_nidxs = inode->i_compr_nidxs;
+
+ inlined_nidxs = inode->i_compr_inlined_nidxs * EROFS_DECOMPR_IDX_SZ;
+ inode->i_inline_datalen = sizeof(struct erofs_extent_header);
+ inode->i_inline_datalen += inlined_nidxs;
+
+ inode->i_inline_align_size = EROFS_INLINE_INDEX_ALIGN_SIZE;
+}
+
+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 (inode->i_dmode == EROFS_INODE_LAYOUT_INLINE) {
+ 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 (inode->i_dmode == EROFS_INODE_LAYOUT_COMPRESSION) {
+ 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);
+}
+
+int mkfs_relocate_sub_inodes(struct erofs_node_info *inode)
+{
+ int ret;
+ 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)
+ return -ENOSPC;
+
+ 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)
+ return -ENOSPC;
+
+ 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);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(d, &inode->i_subdir_head, i_list) {
+ ret = mkfs_relocate_sub_inodes(d);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+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 int 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));
+ return -ENOMEM;
+ }
+
+ list_for_each(pos, &inode->i_subdir_head)
+ {
+ struct erofs_node_info *d;
+ u32 len;
+
+ d = container_of(pos, struct erofs_node_info, i_list);
+ len = strlen(d->i_name);
+
+ if (dentrys_size + EROFS_DIRENT_SIZE + len >
+ EROFS_BLKSIZE) {
+ const u32 addr = inode->i_blkaddr + blk_cnt;
+
+ write_dirents(pbuf, sum, start, pos);
+ ret = dev_write(pbuf,
+ BLKNO_TO_ADDR(addr),
+ EROFS_BLKSIZE);
+ if (ret < 0) {
+ erofs_err(
+ "dev_write inode[%s] error[%s]",
+ inode->i_fullpath,
+ strerror(errno));
+ return ret;
+ }
+
+ 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) {
+ s32 len = write_dirents(pbuf, sum, start, pos);
+
+ inode->i_inline_data = pbuf;
+ inode->i_inline_datalen = len;
+ }
+
+ } 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");
+ return -ENOMEM;
+ }
+
+ list_for_each(pos, &inode->i_subdir_head)
+ {
+ struct erofs_node_info *d;
+ u32 len;
+
+ d = container_of(pos, struct erofs_node_info, i_list);
+ len = strlen(d->i_name);
+ if (dentrys_size + EROFS_DIRENT_SIZE + len >
+ EROFS_BLKSIZE) {
+ const u32 addr = inode->i_blkaddr + blk_cnt;
+
+ write_dirents(pbuf, sum, start, pos);
+ dev_write(pbuf,
+ BLKNO_TO_ADDR(addr),
+ EROFS_BLKSIZE);
+ if (ret < 0) {
+ erofs_err(
+ "dev_write inode[%s] error[%s]",
+ inode->i_fullpath,
+ strerror(errno));
+ return ret;
+ }
+
+ 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) {
+ const u32 addr = inode->i_blkaddr + blk_cnt;
+
+ write_dirents(pbuf, sum, start, pos);
+ ret = dev_write(
+ pbuf, BLKNO_TO_ADDR(addr), EROFS_BLKSIZE);
+ if (ret < 0) {
+ erofs_err("dev_write inode[%s] error[%s]",
+ inode->i_fullpath,
+ strerror(errno));
+ return ret;
+ }
+ }
+
+ free(pbuf);
+
+ } else {
+ erofs_err("inode->i_dmode[%u]mode 1 is not support right now",
+ inode->i_dmode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int 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) {
+ erofs_err("current path=%s filepath=%s",
+ getcwd(NULL, 0),
+ filepath);
+ return -errno;
+ }
+
+ 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));
+ return -errno;
+ }
+
+ for (i = 0; i < page_cnt; i++) {
+ u32 addr;
+
+ ret = read(fd, pbuf, EROFS_BLKSIZE);
+ if (ret < 0) {
+ erofs_err("read inode[%s] error[%s]",
+ filepath,
+ strerror(errno));
+ return -errno;
+ }
+
+ addr = inode->i_blkaddr + i;
+
+ ret = dev_write(
+ pbuf, BLKNO_TO_ADDR(addr), EROFS_BLKSIZE);
+ if (ret < 0) {
+ erofs_err("dev_write inode[%s] ret[%d]",
+ filepath,
+ ret);
+ return ret;
+ }
+ }
+
+ free(pbuf);
+ break;
+
+ case EROFS_INODE_LAYOUT_COMPRESSION:
+ 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));
+ return -errno;
+ }
+
+ for (i = 0; i < nblocks; i++) {
+ u32 addr;
+
+ ret = read(fd, pbuf, EROFS_BLKSIZE);
+ if (ret < 0) {
+ erofs_err("read inode[%s] error[%s]",
+ filepath,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ addr = inode->i_blkaddr + i;
+
+ ret = dev_write(pbuf,
+ BLKNO_TO_ADDR(addr),
+ EROFS_BLKSIZE);
+ if (ret < 0) {
+ erofs_err("dev_write inode[%s] ret[%d]",
+ filepath,
+ ret);
+ return ret;
+ }
+ }
+
+ free(pbuf);
+ }
+
+ if (unaligned > 0) {
+ s32 len;
+
+ inode->i_inline_data = calloc(EROFS_BLKSIZE, 1);
+ if (!inode->i_inline_data) {
+ erofs_err("calloc inode[%s] error[%s]",
+ filepath,
+ strerror(errno));
+ return -errno;
+ }
+
+ (void)lseek(fd, nblocks * EROFS_BLKSIZE, SEEK_SET);
+
+ len = read(fd, inode->i_inline_data, unaligned);
+ if (len < 0) {
+ erofs_err("read inode[%s] error[%s]",
+ filepath,
+ strerror(errno));
+ return -errno;
+ }
+ inode->i_inline_datalen = len;
+ }
+ break;
+
+ default:
+ erofs_err(
+ "Inode[%s] mode error [%d]", filepath, inode->i_dmode);
+ return -EINVAL;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int 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));
+ return -errno;
+ }
+
+ ret = readlink(inode->i_fullpath, pbuf, inode->i_size);
+ if (ret < 0) {
+ erofs_err("readlink inode[%s] error[%s]",
+ inode->i_fullpath,
+ strerror(errno));
+ return -errno;
+ }
+
+ 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));
+ return ret;
+ }
+ 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");
+ return -errno;
+ }
+
+ inode->i_inline_datalen = readlink(
+ inode->i_fullpath, inode->i_inline_data, inode->i_size);
+ if (inode->i_inline_datalen < 0) {
+ perror("readlink");
+ return -errno;
+ }
+
+ break;
+
+ default:
+ erofs_err("Inode mode error [%d]", inode->i_dmode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mkfs_do_write_inodes_data(struct erofs_node_info *inode)
+{
+ int ret;
+ struct list_head *pos;
+
+ switch (inode->i_type) {
+ case EROFS_FT_DIR:
+ ret = mkfs_write_inode_dir(inode);
+ if (ret)
+ return ret;
+ break;
+
+ case EROFS_FT_REG_FILE:
+ ret = mkfs_write_inode_regfile(inode);
+ if (ret)
+ return ret;
+ break;
+
+ case EROFS_FT_SYMLINK:
+ ret = mkfs_write_inode_symfile(inode);
+ if (ret)
+ return ret;
+ 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;
+
+ d = container_of(pos, struct erofs_node_info, i_list);
+ ret = mkfs_do_write_inodes_data(d);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+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;
+ }
+
+ 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) {
+ /* Compress File */
+ case EROFS_INODE_LAYOUT_COMPRESSION:
+ /* Inline softlink or dir or file */
+ case EROFS_INODE_LAYOUT_INLINE:
+ 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..100e788
--- /dev/null
+++ b/mkfs_inode.h
@@ -0,0 +1,83 @@
+/* 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);
+int mkfs_relocate_sub_inodes(struct erofs_node_info *droot);
+int 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 c11c9b6..bb91067 100644
--- a/mkfs_main.c
+++ b/mkfs_main.c
@@ -126,6 +126,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) {
@@ -151,11 +153,38 @@ 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_SUPER_END)));
+ if (err)
+ goto exit;
+
+ err = mkfs_relocate_sub_inodes(proot_node);
+ if (err)
+ goto exit;
+
+ err = mkfs_do_write_inodes_data(proot_node);
+ if (err)
+ goto exit;
+
+ err = erofs_flush_all_blocks();
+ if (err)
+ goto exit;
+
mkfs_update_erofs_header(proot_node->i_base_addr);
+ erofs_info("done");
+
+exit:
dev_close();
mkfs_free_config();
- erofs_info("done");
+ if (err)
+ erofs_err("\tError: Could not format the device!!!\n");
return err;
}
--
2.17.1
More information about the Linux-erofs
mailing list