Omit the `dot` dirent by default if 48bit layout is set.

Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com>
---
 include/erofs/config.h   |  1 +
 include/erofs/internal.h |  1 +
 lib/dir.c                |  2 ++
 lib/inode.c              | 35 +++++++++++++++++++++++++----------
 lib/namei.c              |  3 ++-
 mkfs/main.c              | 14 ++++++++++++++
 6 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/include/erofs/config.h b/include/erofs/config.h
index 92c1467..eb5cad8 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -66,6 +66,7 @@ struct erofs_configure {
        bool c_xattr_name_filter;
        bool c_ovlfs_strip;
        bool c_hard_dereference;
+       bool c_dot_omitted;
 
 #ifdef HAVE_LIBSELINUX
        struct selabel_handle *sehnd;
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index fd8d43d..227e830 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -236,6 +236,7 @@ struct erofs_inode {
        bool opaque;
        /* OVL: non-merge dir that may contain whiteout entries */
        bool whiteouts;
+       bool dot_omitted;
 
        unsigned int xattr_isize;
        unsigned int extent_isize;
diff --git a/lib/dir.c b/lib/dir.c
index d786a5b..3405844 100644
--- a/lib/dir.c
+++ b/lib/dir.c
@@ -150,6 +150,8 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool 
fsck)
                return -ENOTDIR;
 
        ctx->flags &= ~EROFS_READDIR_ALL_SPECIAL_FOUND;
+       if (dir->dot_omitted)
+               ctx->flags |= EROFS_READDIR_DOT_FOUND;
        pos = 0;
        while (pos < dir->i_size) {
                erofs_blk_t lblk = erofs_blknr(sbi, pos);
diff --git a/lib/inode.c b/lib/inode.c
index 7230549..7ded6c1 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -253,21 +253,29 @@ static int erofs_prepare_dir_file(struct erofs_inode *dir,
 {
        struct erofs_sb_info *sbi = dir->sbi;
        struct erofs_dentry *d, *n, **sorted_d;
+       bool dot_omitted = cfg.c_dot_omitted;
        unsigned int i;
        unsigned int d_size = 0;
 
        sorted_d = malloc(nr_subdirs * sizeof(d));
        if (!sorted_d)
                return -ENOMEM;
+
+       dir->dot_omitted = dot_omitted;
        i = 0;
        list_for_each_entry_safe(d, n, &dir->i_subdirs, d_child) {
                list_del(&d->d_child);
+               if (dot_omitted && !strcmp(d->name, ".")) {
+                       erofs_iput(d->inode);
+                       free(d);
+                       continue;
+               }
                sorted_d[i++] = d;
        }
-       DBG_BUGON(i != nr_subdirs);
-       qsort(sorted_d, nr_subdirs, sizeof(d), comp_subdir);
-       for (i = 0; i < nr_subdirs; i++)
-               list_add_tail(&sorted_d[i]->d_child, &dir->i_subdirs);
+       DBG_BUGON(i + dot_omitted != nr_subdirs);
+       qsort(sorted_d, i, sizeof(d), comp_subdir);
+       while (i)
+               list_add(&sorted_d[--i]->d_child, &dir->i_subdirs);
        free(sorted_d);
 
        /* let's calculate dir size */
@@ -642,10 +650,12 @@ int erofs_iflush(struct erofs_inode *inode)
                nlink_1 = false;
                nb = (union erofs_inode_i_nb){};
        }
+       fmt = S_ISDIR(inode->i_mode) && inode->dot_omitted ?
+               1 << EROFS_I_DOT_OMITTED_BIT : 0;
 
        switch (inode->inode_isize) {
        case sizeof(struct erofs_inode_compact):
-               fmt = 0 | (inode->datalayout << 1);
+               fmt |= 0 | (inode->datalayout << 1);
                u.dic.i_xattr_icount = cpu_to_le16(icount);
                u.dic.i_mode = cpu_to_le16(inode->i_mode);
                u.dic.i_nb.nlink = cpu_to_le16(inode->i_nlink);
@@ -670,7 +680,8 @@ int erofs_iflush(struct erofs_inode *inode)
                u.dic.i_format = cpu_to_le16(fmt);
                break;
        case sizeof(struct erofs_inode_extended):
-               u.die.i_format = cpu_to_le16(1 | (inode->datalayout << 1));
+               fmt |= 1 | (inode->datalayout << 1);
+               u.die.i_format = cpu_to_le16(fmt);
                u.die.i_xattr_icount = cpu_to_le16(icount);
                u.die.i_mode = cpu_to_le16(inode->i_mode);
                u.die.i_nlink = cpu_to_le32(inode->i_nlink);
@@ -1543,13 +1554,17 @@ static int erofs_mkfs_handle_directory(struct 
erofs_inode *dir)
 
        /*
         * if there're too many subdirs as compact form, set nlink=1
-        * rather than upgrade to use extented form instead.
+        * rather than upgrade to use extented form instead if possible.
         */
        if (i_nlink > USHRT_MAX &&
-           dir->inode_isize == sizeof(struct erofs_inode_compact))
-               dir->i_nlink = 1;
-       else
+           dir->inode_isize == sizeof(struct erofs_inode_compact)) {
+               if (dir->dot_omitted)
+                       dir->inode_isize = sizeof(struct erofs_inode_extended);
+               else
+                       dir->i_nlink = 1;
+       } else {
                dir->i_nlink = i_nlink;
+       }
 
        return erofs_mkfs_go(sbi, EROFS_MKFS_JOB_DIR, &dir, sizeof(dir));
 
diff --git a/lib/namei.c b/lib/namei.c
index ac14a20..4ccb8ff 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -91,8 +91,9 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
        }
 
        switch (vi->i_mode & S_IFMT) {
-       case S_IFREG:
        case S_IFDIR:
+               vi->dot_omitted = (ifmt >> EROFS_I_DOT_OMITTED_BIT) & 1;
+       case S_IFREG:
        case S_IFLNK:
                vi->u.i_blkaddr = le32_to_cpu(iu.startblk_lo);
                break;
diff --git a/mkfs/main.c b/mkfs/main.c
index 2defa92..49a9eff 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -334,6 +334,16 @@ static int erofs_mkfs_feat_set_48bit(bool en, const char 
*val,
        return 0;
 }
 
+static int erofs_mkfs_feat_set_dot_omitted(bool en, const char *val,
+                                          unsigned int vallen)
+{
+       if (vallen)
+               return -EINVAL;
+
+       cfg.c_dot_omitted = en;
+       return 0;
+}
+
 static struct {
        char *feat;
        int (*set)(bool en, const char *val, unsigned int len);
@@ -345,6 +355,7 @@ static struct {
        {"dedupe", erofs_mkfs_feat_set_dedupe},
        {"fragdedupe", erofs_mkfs_feat_set_fragdedupe},
        {"48bit", erofs_mkfs_feat_set_48bit},
+       {"dot-omitted", erofs_mkfs_feat_set_dot_omitted},
        {NULL, NULL},
 };
 
@@ -1247,6 +1258,9 @@ int main(int argc, char **argv)
                g_sbi.epoch = mkfs_time;
        }
 
+       if (cfg.c_dot_omitted)
+               erofs_sb_set_48bit(&g_sbi);
+
        err = erofs_dev_open(&g_sbi, cfg.c_img_path, O_RDWR |
                                (incremental_mode ? 0 : O_TRUNC));
        if (err) {
-- 
2.43.5


Reply via email to