summaryrefslogtreecommitdiff
path: root/lib/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inode.c')
-rw-r--r--lib/inode.c119
1 files changed, 94 insertions, 25 deletions
diff --git a/lib/inode.c b/lib/inode.c
index 4e1e29f..395caae 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -8,6 +8,7 @@
* with heavy changes by Gao Xiang <gaoxiang25@huawei.com>
*/
#define _GNU_SOURCE
+#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -365,40 +366,81 @@ static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh)
{
struct erofs_inode *const inode = bh->fsprivate;
erofs_off_t off = erofs_btell(bh, false);
-
- /* let's support compact inode currently */
- struct erofs_inode_compact dic = {0};
+ union {
+ struct erofs_inode_compact dic;
+ struct erofs_inode_extended die;
+ } u = { {0}, };
int ret;
- dic.i_format = cpu_to_le16(0 | (inode->datalayout << 1));
- dic.i_mode = cpu_to_le16(inode->i_mode);
- dic.i_nlink = cpu_to_le16(inode->i_nlink);
- dic.i_size = cpu_to_le32((u32)inode->i_size);
+ switch (inode->inode_isize) {
+ case sizeof(struct erofs_inode_compact):
+ u.dic.i_format = cpu_to_le16(0 | (inode->datalayout << 1));
+ u.dic.i_mode = cpu_to_le16(inode->i_mode);
+ u.dic.i_nlink = cpu_to_le16(inode->i_nlink);
+ u.dic.i_size = cpu_to_le32((u32)inode->i_size);
- dic.i_ino = cpu_to_le32(inode->i_ino[0]);
+ u.dic.i_ino = cpu_to_le32(inode->i_ino[0]);
- dic.i_uid = cpu_to_le16((u16)inode->i_uid);
- dic.i_gid = cpu_to_le16((u16)inode->i_gid);
+ u.dic.i_uid = cpu_to_le16((u16)inode->i_uid);
+ u.dic.i_gid = cpu_to_le16((u16)inode->i_gid);
- switch ((inode->i_mode) >> S_SHIFT) {
- case S_IFCHR:
- case S_IFBLK:
- case S_IFIFO:
- case S_IFSOCK:
- dic.i_u.rdev = cpu_to_le32(inode->u.i_rdev);
+ switch ((inode->i_mode) >> S_SHIFT) {
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFIFO:
+ case S_IFSOCK:
+ u.dic.i_u.rdev = cpu_to_le32(inode->u.i_rdev);
+ break;
+
+ default:
+ if (is_inode_layout_compression(inode))
+ u.dic.i_u.compressed_blocks =
+ cpu_to_le32(inode->u.i_blocks);
+ else
+ u.dic.i_u.raw_blkaddr =
+ cpu_to_le32(inode->u.i_blkaddr);
+ break;
+ }
break;
+ case sizeof(struct erofs_inode_extended):
+ u.die.i_format = cpu_to_le16(1 | (inode->datalayout << 1));
+ u.die.i_mode = cpu_to_le16(inode->i_mode);
+ u.die.i_nlink = cpu_to_le32(inode->i_nlink);
+ u.die.i_size = cpu_to_le64(inode->i_size);
+
+ u.die.i_ino = cpu_to_le32(inode->i_ino[0]);
+
+ u.die.i_uid = cpu_to_le16(inode->i_uid);
+ u.die.i_gid = cpu_to_le16(inode->i_gid);
+
+ u.die.i_ctime = cpu_to_le64(inode->i_ctime);
+ u.die.i_ctime_nsec = cpu_to_le32(inode->i_ctime_nsec);
+
+ switch ((inode->i_mode) >> S_SHIFT) {
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFIFO:
+ case S_IFSOCK:
+ u.die.i_u.rdev = cpu_to_le32(inode->u.i_rdev);
+ break;
- default:
- if (is_inode_layout_compression(inode))
- dic.i_u.compressed_blocks =
- cpu_to_le32(inode->u.i_blocks);
- else
- dic.i_u.raw_blkaddr =
- cpu_to_le32(inode->u.i_blkaddr);
+ default:
+ if (is_inode_layout_compression(inode))
+ u.die.i_u.compressed_blocks =
+ cpu_to_le32(inode->u.i_blocks);
+ else
+ u.die.i_u.raw_blkaddr =
+ cpu_to_le32(inode->u.i_blkaddr);
+ break;
+ }
break;
+ default:
+ erofs_err("unsupported on-disk inode version of nid %llu",
+ (unsigned long long)inode->nid);
+ BUG_ON(1);
}
- ret = dev_write(&dic, off, sizeof(struct erofs_inode_compact));
+ ret = dev_write(&u, off, inode->inode_isize);
if (ret)
return false;
off += inode->inode_isize;
@@ -578,6 +620,21 @@ out:
return 0;
}
+static bool erofs_should_use_inode_extended(struct erofs_inode *inode)
+{
+ if (cfg.c_force_inodeversion == FORCE_INODE_EXTENDED)
+ return true;
+ if (inode->i_size > UINT_MAX)
+ return true;
+ if (inode->i_uid > USHRT_MAX)
+ return true;
+ if (inode->i_gid > USHRT_MAX)
+ return true;
+ if (inode->i_nlink > USHRT_MAX)
+ return true;
+ return false;
+}
+
static u32 erofs_new_encode_dev(dev_t dev)
{
const unsigned int major = major(dev);
@@ -593,6 +650,8 @@ int erofs_fill_inode(struct erofs_inode *inode,
inode->i_mode = st->st_mode;
inode->i_uid = st->st_uid;
inode->i_gid = st->st_gid;
+ inode->i_ctime = sbi.build_time;
+ inode->i_ctime_nsec = sbi.build_time_nsec;
inode->i_nlink = 1; /* fix up later if needed */
switch (inode->i_mode & S_IFMT) {
@@ -616,7 +675,17 @@ int erofs_fill_inode(struct erofs_inode *inode,
inode->i_srcpath[sizeof(inode->i_srcpath) - 1] = '\0';
inode->i_ino[1] = st->st_ino;
- inode->inode_isize = sizeof(struct erofs_inode_compact);
+
+ if (erofs_should_use_inode_extended(inode)) {
+ if (cfg.c_force_inodeversion == FORCE_INODE_COMPACT) {
+ erofs_err("file %s cannot be in compact form",
+ inode->i_srcpath);
+ return -EINVAL;
+ }
+ inode->inode_isize = sizeof(struct erofs_inode_extended);
+ } else {
+ inode->inode_isize = sizeof(struct erofs_inode_compact);
+ }
list_add(&inode->i_hash,
&inode_hashtable[st->st_ino % NR_INODE_HASHTABLE]);