On Thu, 20 Jul 2023 21:14:22 +0800
<zhaoyi...@sjtu.edu.cn> wrote:

> Thank you for the reply!
> 
> As Xiang pointed out, we believe that uncompressed support for EROFS is still 
> valuable, so I would be very grateful if this support could be merged into 
> the GRUB mainline. 

Yes, I believe this will get merged into master. The question is
"when", after or before release. Now that I know that the compression is
on a per-file basis and so this version can still be widely used (with
the condition that the kernel and initrd are uncompressed by EROFS), I
am in support of having this included in the upcoming release.
Ultimately the decision is Daniel's though.

> By the way, we expect to bring support for the EROFS compression part within 
> a few weeks. However, AFAIK, GRUB lacks generic support for lz4 compression 
> algorithms. Would it be more appropriate to introduce a dedicated lz4 library 
> for EROFS, like zfs, or generic lz4 support for grub?

I have not looked into ZFS's usage of its internal library, nor how
hard it would be to make it a separate module. But I prefer the
separate module approach. Perhaps Daniel can speak to his preferred
method.

Glenn

> > -----Original Message-----
> > From: Glenn Washburn <developm...@efficientek.com>
> > Sent: Monday, July 17, 2023 11:51 AM
> > To: Yifan Zhao <zhaoyi...@sjtu.edu.cn>
> > Cc: The development of GNU GRUB <grub-devel@gnu.org>;
> > hsiang...@linux.alibaba.com; jeffl...@linux.alibaba.com
> > Subject: Re: [PATCH 1/2] fs/erofs: Add support for EROFS
> > 
> > On Mon, 17 Jul 2023 00:03:08 +0800
> > Yifan Zhao <zhaoyi...@sjtu.edu.cn> wrote:
> > 
> > > EROFS is a lightweight read-only filesystem designed for performance
> > > which has already been widely used in several scenarios, such as
> > > Android system partitions, container images, and rootfs for embedded
> > devices.
> > >
> > > This patch brings EROFS uncompressed support. Now, it's possible to
> > > boot directly through GRUB with an EROFS rootfs.
> > >
> > > EROFS compressed support will be developed later since it has more
> > > work to polish.
> > 
> > I would expect that a very small minority are using EROFS without
> > compression.
> > Does that also seem true to you? This is relevant because I believe GRUB is 
> > in
> > a feature freeze, but if there were a compelling reason to include this in 
> > the
> > upcoming release, Daniel might make an exception (just guessing). On the
> > one hand, in favor of including the current code without compression in the
> > next release is that its simple enough and doesn't touch existing code, so a
> > bug should have minor impact on the rest of GRUB. On the other hand, if
> > there is a low probability of its use, perhaps its not worth it. As it 
> > stands, it
> > seems that GRUB is being released every couple years.
> > 
> > When you create an updated patch series, it would be much appreciated if
> > you use --range-diff or --interdiff so that reviewers (me) can verify more
> > easily the changes.
> > 
> > >
> > > Signed-off-by: Yifan Zhao <zhaoyi...@sjtu.edu.cn>
> > > ---
> > > The link here shows how to boot the kernel from the EROFS partition with
> > this patch.
> > > https://precious-celery-715.notion.site/Demo-of-booting-kernel-in-a-ER
> > > OFS-partition-c6d199f937a2489bafd03d3083c294b5
> > >
> > >  INSTALL                     |   8 +-
> > >  Makefile.util.def           |   1 +
> > >  docs/grub.texi              |   4 +-
> > >  grub-core/Makefile.core.def |   5 +
> > >  grub-core/fs/erofs.c        | 971 ++++++++++++++++++++++++++++++++++++
> > >  grub-core/kern/misc.c       |  14 +
> > >  include/grub/misc.h         |   1 +
> > >  7 files changed, 998 insertions(+), 6 deletions(-)  create mode
> > > 100644 grub-core/fs/erofs.c
> > >
> > > diff --git a/INSTALL b/INSTALL
> > > index b93fe9c61..1939e4745 100644
> > > --- a/INSTALL
> > > +++ b/INSTALL
> > > @@ -77,15 +77,15 @@ Prerequisites for make-check:
> > >
> > >  * If running a Linux kernel the following modules must be loaded:
> > >    - fuse, loop
> > > -  - btrfs, ext4, f2fs, fat, hfs, hfsplus, jfs, mac-roman, minix,
> > > nilfs2,
> > > +  - btrfs, erofs, ext4, f2fs, fat, hfs, hfsplus, jfs, mac-roman,
> > > + minix, nilfs2,
> > >      reiserfs, udf, xfs
> > >    - On newer kernels, the exfat kernel modules may be used instead of the
> > >      exfat FUSE filesystem
> > >  * The following are Debian named packages required mostly for the full
> > >    suite of filesystem testing (but some are needed by other tests as 
> > > well):
> > > -  - btrfs-progs, dosfstools, e2fsprogs, exfat-utils, f2fs-tools, 
> > > genromfs,
> > > -    hfsprogs, jfsutils, nilfs-tools, ntfs-3g, reiserfsprogs, 
> > > squashfs-tools,
> > > -    reiserfsprogs, udftools, xfsprogs, zfs-fuse
> > > +  - btrfs-progs, dosfstools, erofs_utils, e2fsprogs, exfat-utils, 
> > > f2fs-tools,
> > > +    genromfs, hfsprogs, jfsutils, nilfs-tools, ntfs-3g, reiserfsprogs,
> > > +    squashfs-tools, reiserfsprogs, udftools, xfsprogs, zfs-fuse
> > 
> > Thank you for updating the documentation. It would be nice to also update
> > docs/grub.texi where appropriate and note that there is no compression
> > support. I see two places that could use an update (case-insensitive search
> > for "btrfs" should find them).
> > 
> 
> Thanks for pointing it out. I will note that EROFS support is incomplete 
> currently. 
> 
> > >    - exfat-fuse, if not using the exfat kernel module
> > >    - gzip, lzop, xz-utils
> > >    - attr, cpio, g++, gawk, parted, recode, tar, util-linux diff --git
> > > a/Makefile.util.def b/Makefile.util.def index 1e9a13d3e..ca2a32a7f
> > > 100644
> > > --- a/Makefile.util.def
> > > +++ b/Makefile.util.def
> > > @@ -98,6 +98,7 @@ library = {
> > >    common = grub-core/fs/cpio_be.c;
> > >    common = grub-core/fs/odc.c;
> > >    common = grub-core/fs/newc.c;
> > > +  common = grub-core/fs/erofs.c;
> > >    common = grub-core/fs/ext2.c;
> > >    common = grub-core/fs/fat.c;
> > >    common = grub-core/fs/exfat.c;
> > > diff --git a/docs/grub.texi b/docs/grub.texi index
> > > b81267980..20c119c96 100644
> > > --- a/docs/grub.texi
> > > +++ b/docs/grub.texi
> > > @@ -361,7 +361,7 @@ blocklist notation. The currently supported
> > > filesystem types are @dfn{Amiga  Fast FileSystem (AFFS)}, @dfn{AtheOS
> > > fs}, @dfn{BeFS},  @dfn{BtrFS} (including raid0, raid1, raid10, gzip
> > > and lzo),  @dfn{cpio} (little- and big-endian bin, odc and newc
> > > variants), -@dfn{Linux ext2/ext3/ext4}, @dfn{DOS FAT12/FAT16/FAT32},
> > > +@dfn{EROFS}, @dfn{Linux ext2/ext3/ext4}, @dfn{DOS
> > FAT12/FAT16/FAT32},
> > >  @dfn{exFAT}, @dfn{F2FS}, @dfn{HFS}, @dfn{HFS+},  @dfn{ISO9660}
> > > (including Joliet, Rock-ridge and multi-chunk files),  @dfn{JFS},
> > > @dfn{Minix fs} (versions 1, 2 and 3), @dfn{nilfs2}, @@ -6212,7 +6212,7
> > > @@ assumed to be encoded in UTF-8.
> > >  NTFS, JFS, UDF, HFS+, exFAT, long filenames in FAT, Joliet part of
> > >  ISO9660 are treated as UTF-16 as per specification. AFS and BFS are
> > > read  as UTF-8, again according to specification. BtrFS, cpio, tar,
> > > squash4, minix, -minix2, minix3, ROMFS, ReiserFS, XFS, ext2, ext3,
> > > ext4, FAT (short names),
> > > +minix2, minix3, ROMFS, ReiserFS, XFS, EROFS, ext2, ext3, ext4, FAT
> > > +(short names),
> > >  F2FS, RockRidge part of ISO9660, nilfs2, UFS1, UFS2 and ZFS are
> > > assumed  to be UTF-8. This might be false on systems configured with
> > > legacy charset  but as long as the charset used is superset of ASCII
> > > you should be able to diff --git a/grub-core/Makefile.core.def
> > > b/grub-core/Makefile.core.def index d2cf29584..eccf9b6cf 100644
> > > --- a/grub-core/Makefile.core.def
> > > +++ b/grub-core/Makefile.core.def
> > > @@ -1438,6 +1438,11 @@ module = {
> > >    common = fs/odc.c;
> > >  };
> > >
> > > +module = {
> > > +  name = erofs;
> > > +  common = fs/erofs.c;
> > > +};
> > > +
> > >  module = {
> > >    name = ext2;
> > >    common = fs/ext2.c;
> > > diff --git a/grub-core/fs/erofs.c b/grub-core/fs/erofs.c new file mode
> > > 100644 index 000000000..f1366ce05
> > > --- /dev/null
> > > +++ b/grub-core/fs/erofs.c
> > > @@ -0,0 +1,971 @@
> > > +/* erofs.c - Enhanced Read-Only File System */
> > > +/*
> > > + *  GRUB  --  GRand Unified Bootloader
> > > + *  Copyright (C) 2023 Free Software Foundation, Inc.
> > > + *
> > > + *  GRUB is free software: you can redistribute it and/or modify
> > > + *  it under the terms of the GNU General Public License as published
> > > +by
> > > + *  the Free Software Foundation, either version 3 of the License, or
> > > + *  (at your option) any later version.
> > > + *
> > > + *  GRUB is distributed in the hope that it will be useful,
> > > + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > + *  GNU General Public License for more details.
> > > + *
> > > + *  You should have received a copy of the GNU General Public License
> > > + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> > > + */
> > > +
> > > +#include <grub/disk.h>
> > > +#include <grub/dl.h>
> > > +#include <grub/err.h>
> > > +#include <grub/file.h>
> > > +#include <grub/fs.h>
> > > +#include <grub/fshelp.h>
> > > +#include <grub/misc.h>
> > > +#include <grub/mm.h>
> > > +#include <grub/safemath.h>
> > > +#include <grub/types.h>
> > > +
> > > +GRUB_MOD_LICENSE ("GPLv3+");
> > > +
> > > +#define ROUND_UP(x, y) ({ grub_divmod64 (x + (y - 1), y, NULL) * y;
> > > +})
> > 
> > Is there a reason ALIGN_UP is not used instead of the above macro?
> > 
> 
> I miss the useful macro and will fix it in an updated patch.
> 
> > > +
> > > +#define EROFS_SUPER_OFFSET (1024)
> > > +#define EROFS_MAGIC 0xE0F5E1E2
> > > +#define EROFS_ISLOTBITS (5)
> > > +
> > > +#define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE 0x00000004 #define
> > > +EROFS_ALL_FEATURE_INCOMPAT
> > (EROFS_FEATURE_INCOMPAT_CHUNKED_FILE)
> > > +
> > > +struct grub_erofs_super
> > > +{
> > > +  grub_uint32_t magic;
> > > +  grub_uint32_t checksum;
> > > +  grub_uint32_t feature_compat;
> > > +  grub_uint8_t blkszbits;
> > 
> > Perhaps rename to "log2_blksz".
> 
> Changes made as required.
> 
> > 
> > > +  grub_uint8_t sb_extslots;
> > > +
> > > +  grub_uint16_t root_nid;
> > > +  grub_uint64_t inos;
> > > +
> > > +  grub_uint64_t build_time;
> > > +  grub_uint32_t build_time_nsec;
> > > +  grub_uint32_t blocks;
> > > +  grub_uint32_t meta_blkaddr;
> > > +  grub_uint32_t xattr_blkaddr;
> > > +  grub_uint8_t uuid[16];
> > > +  grub_uint8_t volume_name[16];
> > > +  grub_uint32_t feature_incompat;
> > > +
> > > +  union
> > > +  {
> > > +    grub_uint16_t available_compr_algs;
> > > +    grub_uint16_t lz4_max_distance;
> > > +  } GRUB_PACKED u1;
> > > +
> > > +  grub_uint16_t extra_devices;
> > > +  grub_uint16_t devt_slotoff;
> > > +  grub_uint8_t dirblkbits;
> > 
> > And maybe log2_dirblksz? And I notice that this is never used. I know 
> > nothing
> > about EROFS, but this looks like it has to do with directories. What is this
> > used for, if its not needed in the directory reading code below?
> 
> In a future version, EROFS will support directory block size being a multiple 
> of base blksz, because large dir block size improves directory fanout 
> efficiency.
> Currently, this field is reserved and its value must be 0. Changed its name 
> as you required.
> 
> > > +  grub_uint8_t xattr_prefix_count;
> > > +  grub_uint32_t xattr_prefix_start;
> > > +  grub_uint64_t packed_nid;
> > > +  grub_uint8_t reserved2[24];
> > > +} GRUB_PACKED;
> > > +
> > > +#define EROFS_INODE_LAYOUT_COMPACT 0
> > > +#define EROFS_INODE_LAYOUT_EXTENDED 1
> > > +
> > > +enum
> > > +{
> > > +  EROFS_INODE_FLAT_PLAIN = 0,
> > > +  EROFS_INODE_COMPRESSED_FULL = 1,
> > > +  EROFS_INODE_FLAT_INLINE = 2,
> > > +  EROFS_INODE_COMPRESSED_COMPACT = 3,
> > > +  EROFS_INODE_CHUNK_BASED = 4,
> > > +  EROFS_INODE_DATALAYOUT_MAX
> > > +};
> > > +
> > > +#define EROFS_I_VERSION_MASKS 0x01
> > > +#define EROFS_I_DATALAYOUT_MASKS 0x07
> > > +
> > > +#define EROFS_I_VERSION_BIT 0
> > > +#define EROFS_I_DATALAYOUT_BIT 1
> > > +
> > > +struct grub_erofs_inode_chunk_info
> > > +{
> > > +  grub_uint16_t format;
> > > +  grub_uint16_t reserved;
> > > +} GRUB_PACKED;
> > > +
> > > +#define EROFS_CHUNK_FORMAT_BLKBITS_MASK 0x001F #define
> > > +EROFS_CHUNK_FORMAT_INDEXES 0x0020
> > > +
> > > +#define EROFS_BLOCK_MAP_ENTRY_SIZE 4
> > > +
> > > +#define EROFS_NULL_ADDR -1
> > > +
> > > +struct grub_erofs_inode_chunk_index
> > > +{
> > > +  grub_uint16_t advise;
> > > +  grub_uint16_t device_id;
> > > +  grub_uint32_t blkaddr;
> > > +};
> > > +
> > > +union grub_erofs_inode_i_u
> > > +{
> > > +  grub_uint32_t compressed_blocks;
> > > +  grub_uint32_t raw_blkaddr;
> > > +
> > > +  grub_uint32_t rdev;
> > > +
> > > +  struct grub_erofs_inode_chunk_info c; };
> > > +
> > > +struct grub_erofs_inode_compact
> > > +{
> > > +  grub_uint16_t i_format;
> > > +
> > > +  grub_uint16_t i_xattr_icount;
> > > +  grub_uint16_t i_mode;
> > > +  grub_uint16_t i_nlink;
> > > +  grub_uint32_t i_size;
> > > +  grub_uint32_t i_reserved;
> > > +
> > > +  union grub_erofs_inode_i_u i_u;
> > > +
> > > +  grub_uint32_t i_ino;
> > > +  grub_uint16_t i_uid;
> > > +  grub_uint16_t i_gid;
> > > +  grub_uint32_t i_reserved2;
> > > +} GRUB_PACKED;
> > > +
> > > +struct grub_erofs_inode_extended
> > > +{
> > > +  grub_uint16_t i_format;
> > > +
> > > +  grub_uint16_t i_xattr_icount;
> > > +  grub_uint16_t i_mode;
> > > +  grub_uint16_t i_reserved;
> > > +  grub_uint64_t i_size;
> > > +
> > > +  union grub_erofs_inode_i_u i_u;
> > > +
> > > +  grub_uint32_t i_ino;
> > > +
> > > +  grub_uint32_t i_uid;
> > > +  grub_uint32_t i_gid;
> > > +  grub_uint64_t i_mtime;
> > > +  grub_uint32_t i_mtime_nsec;
> > > +  grub_uint32_t i_nlink;
> > > +  grub_uint8_t i_reserved2[16];
> > > +} GRUB_PACKED;
> > > +
> > > +enum
> > > +{
> > > +  EROFS_FT_UNKNOWN,
> > > +  EROFS_FT_REG_FILE,
> > > +  EROFS_FT_DIR,
> > > +  EROFS_FT_CHRDEV,
> > > +  EROFS_FT_BLKDEV,
> > > +  EROFS_FT_FIFO,
> > > +  EROFS_FT_SOCK,
> > > +  EROFS_FT_SYMLINK,
> > > +  EROFS_FT_MAX
> > > +};
> > > +
> > > +#define EROFS_NAME_LEN 255
> > > +
> > > +struct grub_erofs_dirent
> > > +{
> > > +  grub_uint64_t nid;
> > > +  grub_uint16_t nameoff;
> > > +  grub_uint8_t file_type;
> > > +  grub_uint8_t reserved;
> > > +} GRUB_PACKED;
> > > +
> > > +enum
> > > +{
> > > +  BH_Meta,
> > > +  BH_Mapped,
> > > +};
> > > +
> > > +#define EROFS_MAP_MAPPED (1 << BH_Mapped)
> > > +
> > > +struct grub_erofs_map_blocks
> > > +{
> > > +  grub_off_t m_pa, m_la;
> > > +  grub_off_t m_plen, m_llen;
> > > +  grub_uint32_t m_flags;
> > > +};
> > > +
> > > +struct grub_erofs_xattr_ibody_header
> > > +{
> > > +  grub_uint32_t h_reserved;
> > > +  grub_uint8_t h_shared_count;
> > > +  grub_uint8_t h_reserved2[7];
> > > +  grub_uint32_t h_shared_xattrs[0];
> > > +};
> > > +
> > > +struct grub_fshelp_node
> > > +{
> > > +  struct grub_erofs_data *data;
> > > +  struct grub_erofs_inode_extended inode;
> > > +
> > > +  grub_uint64_t ino;
> > > +  grub_uint8_t inode_type;
> > > +  grub_uint8_t inode_datalayout;
> > > +
> > > +  /* if the inode has been read into memory? */
> > > +  bool inode_read;
> > > +};
> > > +
> > > +struct grub_erofs_data
> > > +{
> > > +  grub_disk_t disk;
> > > +  struct grub_erofs_super sb;
> > > +
> > > +  struct grub_fshelp_node inode;
> > > +};
> > > +
> > > +#define erofs_blocksz(data) (1u << data->sb.blkszbits)
> > > +
> > > +static inline grub_uint64_t
> > > +erofs_iloc (grub_fshelp_node_t node)
> > > +{
> > > +  struct grub_erofs_super *sb = &node->data->sb;
> > > +
> > > +  return (grub_le_to_cpu32 (sb->meta_blkaddr) << sb->blkszbits) +
> > > +         (node->ino << EROFS_ISLOTBITS); }
> > > +
> > > +static grub_err_t
> > > +grub_erofs_read_inode (struct grub_erofs_data *data,
> > > +grub_fshelp_node_t node) {
> > > +  struct grub_erofs_inode_compact *dic;
> > > +  grub_err_t err;
> > > +  grub_uint64_t addr = erofs_iloc (node);
> > > +
> > > +  dic = (struct grub_erofs_inode_compact *)&node->inode;
> > > +
> > > +  err = grub_disk_read (data->disk, addr >> GRUB_DISK_SECTOR_BITS,
> > > +                        addr & (GRUB_DISK_SECTOR_SIZE - 1),
> > 
> > 8 spaces should be converted to tabs.
> > 
> > > +                        sizeof (struct grub_erofs_inode_compact),
> > > + dic);  if (err)
> > > +    return err;
> > > +
> > > +  node->inode_type =
> > > +      (dic->i_format >> EROFS_I_VERSION_BIT) & EROFS_I_VERSION_MASKS;
> > > + node->inode_datalayout =
> > > +      (dic->i_format >> EROFS_I_DATALAYOUT_BIT) &
> > > + EROFS_I_DATALAYOUT_MASKS;
> > > +
> > > +  switch (node->inode_type)
> > > +    {
> > > +    case EROFS_INODE_LAYOUT_EXTENDED:
> > > +      addr += sizeof (struct grub_erofs_inode_compact);
> > > +      err = grub_disk_read (
> > > +          data->disk, addr >> GRUB_DISK_SECTOR_BITS,
> > > +          addr & (GRUB_DISK_SECTOR_SIZE - 1),
> > > +          sizeof (struct grub_erofs_inode_extended) -
> > > +              sizeof (struct grub_erofs_inode_compact),
> > > +          (char *)dic + sizeof (struct grub_erofs_inode_compact));
> > > +      if (err)
> > > +        return err;
> > > +      break;
> > > +    case EROFS_INODE_LAYOUT_COMPACT:
> > > +      break;
> > > +    default:
> > > +      return grub_error (GRUB_ERR_BAD_FS,
> > > +                         "invalid inode version %u @ inode %" 
> > > PRIuGRUB_UINT64_T,
> > > +                         node->inode_type, node->ino);
> > > +    }
> > > +
> > > +  node->inode_read = true;
> > > +
> > > +  return 0;
> > > +}
> > > +
> > > +static inline grub_uint64_t
> > > +erofs_inode_size (grub_fshelp_node_t node) {
> > > +  return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
> > > +             ? sizeof (struct grub_erofs_inode_compact)
> > > +             : sizeof (struct grub_erofs_inode_extended); }
> > > +
> > > +static inline grub_uint64_t
> > > +erofs_inode_file_size (grub_fshelp_node_t node) {
> > > +  struct grub_erofs_inode_compact *dic =
> > > +      (struct grub_erofs_inode_compact *)&node->inode;
> > > +
> > > +  return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
> > > +             ? grub_le_to_cpu32 (dic->i_size)
> > > +             : grub_le_to_cpu64 (node->inode.i_size); }
> > > +
> > > +static inline grub_uint32_t
> > > +erofs_inode_xattr_ibody_size (grub_fshelp_node_t node) {
> > > +  grub_uint16_t cnt = grub_le_to_cpu16 (node->inode.i_xattr_icount);
> > > +
> > > +  return cnt ? sizeof (struct grub_erofs_xattr_ibody_header) +
> > > +                   (cnt - 1) * sizeof (grub_uint32_t)
> > > +             : 0;
> > > +}
> > > +
> > > +static inline grub_uint64_t
> > > +erofs_inode_mtime (grub_fshelp_node_t node) {
> > > +  return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
> > > +             ? grub_le_to_cpu64 (node->data->sb.build_time)
> > > +             : grub_le_to_cpu64 (node->inode.i_mtime); }
> > > +
> > > +static grub_err_t
> > > +grub_erofs_map_blocks_flatmode (grub_fshelp_node_t node,
> > > +                                struct grub_erofs_map_blocks *map) {
> > > +  grub_off_t nblocks, lastblk, file_size;
> > > +  grub_off_t tailendpacking =
> > > +      (node->inode_datalayout == EROFS_INODE_FLAT_INLINE) ? 1 : 0;
> > > +  grub_uint32_t blocksz = erofs_blocksz (node->data);
> > > +
> > > +  file_size = erofs_inode_file_size (node);  nblocks = grub_divmod64
> > > + (file_size + blocksz - 1, blocksz, NULL);
> > 
> > Would it not be better to do the following?
> > 
> >   nblocks = (file_size + (1U << node->data->sb.blkszbits)) >> node->data-
> > >sb.blkszbits;
> > 
> 
> Yes, I think it would be
> 
> nblocks = (file_size + blocksz - 1) >> node->data->sb.blkszbits;
> 
> > And if so, then maybe create a erofs_log_blocksz() macro.
> > 
> > > +  lastblk = nblocks - tailendpacking;
> > > +
> > > +  map->m_flags = EROFS_MAP_MAPPED;
> > > +
> > > +  if (map->m_la < lastblk * blocksz)
> > 
> > s/lastblk * blocksz/(lastblk * blocksz)/
> > 
> > > +    {
> > > +      map->m_pa =
> > > +          grub_le_to_cpu32 (node->inode.i_u.raw_blkaddr) * blocksz + map-
> > >m_la;
> > > +      map->m_plen = lastblk * blocksz - map->m_la;
> > > +    }
> > > +  else if (tailendpacking)
> > > +    {
> > > +      map->m_pa = erofs_iloc (node) + erofs_inode_size (node) +
> > > +                  erofs_inode_xattr_ibody_size (node) + map->m_la %
> > > + blocksz;
> > 
> > s/map->m_la % blocksz/(map->m_la % blocksz)/
> > 
> > > +      map->m_plen = file_size - map->m_la;
> > > +
> > > +      if (map->m_pa % blocksz + map->m_plen > blocksz)
> > 
> > s/map->m_pa % blocksz + map->m_plen/((map->m_pa % blocksz) + map-
> > >m_plen)/
> > 
> > Add explicit parenthesis for the code below too.
> > 
> 
> I'll add them.
> 
> > > +        return grub_error (
> > > +            GRUB_ERR_BAD_FS,
> > > +            "inline data cross block boundary @ inode %" 
> > > PRIuGRUB_UINT64_T,
> > > +            node->ino);
> > > +    }
> > > +  else
> > > +    {
> > 
> > This parenthesis is unneeded.
> 
> Yep.
> 
> > 
> > > +      return grub_error (GRUB_ERR_BAD_FS,
> > > +                         "internal error: invalid map->m_la=%" 
> > > PRIuGRUB_UINT64_T
> > > +                         " @ inode %" PRIuGRUB_UINT64_T,
> > > +                         map->m_la, node->ino);
> > > +    }
> > > +
> > > +  map->m_llen = map->m_plen;
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +static grub_err_t
> > > +grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
> > > +                                 struct grub_erofs_map_blocks *map) {
> > > +  grub_uint16_t chunk_format = grub_le_to_cpu16
> > > +(node->inode.i_u.c.format);
> > > +  grub_off_t unit, pos;
> > > +  grub_uint64_t chunknr;
> > > +  grub_uint8_t chunkbits;
> > > +  grub_err_t err;
> > > +
> > > +  if (chunk_format & EROFS_CHUNK_FORMAT_INDEXES)
> > > +    unit = sizeof (struct grub_erofs_inode_chunk_index);  else
> > > +    unit = EROFS_BLOCK_MAP_ENTRY_SIZE;
> > > +
> > > +  chunkbits = node->data->sb.blkszbits +
> > > +              (chunk_format & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
> > > +
> > > +  chunknr = map->m_la >> chunkbits;
> > > +  pos = ROUND_UP (erofs_iloc (node) + erofs_inode_size (node) +
> > > +                      erofs_inode_xattr_ibody_size (node),
> > > +                  unit);
> > > +  pos += chunknr * unit;
> > > +
> > > +  map->m_la = chunknr << chunkbits;
> > > +  map->m_plen = grub_min (1ULL << chunkbits,
> > > +                          ROUND_UP (erofs_inode_file_size (node) - 
> > > map->m_la,
> > > +                                    erofs_blocksz (node->data)));
> > > +
> > > +  if (chunk_format & EROFS_CHUNK_FORMAT_INDEXES)
> > > +    {
> > > +      struct grub_erofs_inode_chunk_index idx;
> > > +      grub_uint32_t blkaddr;
> > > +
> > > +      err = grub_disk_read (node->data->disk, pos >>
> > GRUB_DISK_SECTOR_BITS,
> > > +                            pos & (GRUB_DISK_SECTOR_SIZE - 1), unit, 
> > > &idx);
> > > +      if (err)
> > > +        return err;
> > > +
> > > +      blkaddr = grub_le_to_cpu32 (idx.blkaddr);
> > > +
> > > +      if (blkaddr == (grub_uint32_t)EROFS_NULL_ADDR)
> > 
> > It is preferred to have a space after the cast parenthesis, elsewhere also.
> 
> I've overlooked it. Thanks for pointing it out.
> 
> > > +        {
> > > +          map->m_pa = 0;
> > > +          map->m_flags = 0;
> > > +        }
> > > +      else
> > > +        {
> > > +          map->m_pa = blkaddr << node->data->sb.blkszbits;
> > > +          map->m_flags = EROFS_MAP_MAPPED;
> > > +        }
> > > +    }
> > > +  else
> > > +    {
> > > +      grub_uint32_t blkaddr_le, blkaddr;
> > > +
> > > +      err =
> > > +          grub_disk_read (node->data->disk, pos >> GRUB_DISK_SECTOR_BITS,
> > > +                          pos & (GRUB_DISK_SECTOR_SIZE - 1), unit, 
> > > &blkaddr_le);
> > > +      if (err)
> > > +        return err;
> > > +
> > > +      blkaddr = grub_le_to_cpu32 (blkaddr_le);
> > > +      if (blkaddr == (grub_uint32_t)EROFS_NULL_ADDR)
> > > +        {
> > > +          map->m_pa = 0;
> > > +          map->m_flags = 0;
> > > +        }
> > > +      else
> > > +        {
> > > +          map->m_pa = blkaddr << node->data->sb.blkszbits;
> > > +          map->m_flags = EROFS_MAP_MAPPED;
> > > +        }
> > > +    }
> > > +
> > > +  map->m_llen = map->m_plen;
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +static grub_err_t
> > > +grub_erofs_map_blocks (grub_fshelp_node_t node,
> > > +                       struct grub_erofs_map_blocks *map) {
> > > +  if (map->m_la >= erofs_inode_file_size (node))
> > > +    {
> > > +      map->m_llen = map->m_plen = 0;
> > > +      map->m_pa = 0;
> > > +      map->m_flags = 0;
> > > +      return GRUB_ERR_NONE;
> > > +    }
> > > +
> > > +  if (node->inode_datalayout != EROFS_INODE_CHUNK_BASED)
> > > +    return grub_erofs_map_blocks_flatmode (node, map);
> > > +  else
> > > +    return grub_erofs_map_blocks_chunkmode (node, map); }
> > > +
> > > +static grub_err_t
> > > +grub_erofs_read_raw_data (grub_fshelp_node_t node, char *buf,
> > grub_off_t size,
> > > +                          grub_off_t offset, grub_off_t *bytes) {
> > > +  struct grub_erofs_map_blocks map;
> > > +  grub_err_t err;
> > > +
> > > +  if (bytes)
> > > +    *bytes = 0;
> > > +
> > > +  if (!node->inode_read)
> > > +    {
> > > +      err = grub_erofs_read_inode (node->data, node);
> > > +      if (err)
> > > +        return err;
> > > +    }
> > > +
> > > +  grub_memset (&map, 0, sizeof (map));
> > > +
> > > +  grub_off_t cur = offset;
> > > +  while (cur < offset + size)
> > > +    {
> > > +      char *const estart = buf + cur - offset;
> > > +      grub_off_t eend, moff = 0;
> > > +
> > > +      map.m_la = cur;
> > > +      err = grub_erofs_map_blocks (node, &map);
> > > +      if (err)
> > > +        return err;
> > > +
> > > +      eend = grub_min (offset + size, map.m_la + map.m_llen);
> > > +      if (!(map.m_flags & EROFS_MAP_MAPPED))
> > > +        {
> > > +          if (!map.m_llen)
> > > +            {
> > > +              /* reached EOF */
> > > +              grub_memset (estart, 0, offset + size - cur);
> > > +              cur = offset + size;
> > > +              continue;
> > > +            }
> > > +
> > > +          /* Hole */
> > > +          grub_memset (estart, 0, eend - cur);
> > > +          cur = eend;
> > > +          if (bytes)
> > > +            *bytes += eend - cur;
> > > +          continue;
> > > +        }
> > > +
> > > +      if (cur > map.m_la)
> > > +        {
> > > +          moff = cur - map.m_la;
> > > +          map.m_la = cur;
> > > +        }
> > > +
> > > +      err = grub_disk_read (node->data->disk,
> > > +                            (map.m_pa + moff) >> GRUB_DISK_SECTOR_BITS,
> > > +                            (map.m_pa + moff) & (GRUB_DISK_SECTOR_SIZE - 
> > > 1),
> > > +                            eend - map.m_la, estart);
> > > +      if (err)
> > > +        return err;
> > > +
> > > +      if (bytes)
> > > +        *bytes += eend - map.m_la;
> > > +
> > > +      cur = eend;
> > > +    }
> > > +
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +static int
> > > +grub_erofs_iterate_dir (grub_fshelp_node_t dir,
> > > +                        grub_fshelp_iterate_dir_hook_t hook, void
> > > +*hook_data) {
> > > +  grub_off_t offset = 0, file_size;
> > > +  grub_err_t err;
> > > +  grub_uint32_t blocksz = erofs_blocksz (dir->data);
> > > +  char *buf;
> > > +
> > > +  if (!dir->inode_read)
> > > +    {
> > > +      err = grub_erofs_read_inode (dir->data, dir);
> > > +      if (err)
> > > +        return 0;
> > > +    }
> > > +
> > > +  file_size = erofs_inode_file_size (dir);  buf = grub_malloc
> > > + (blocksz);  if (!buf)
> > > +    {
> > > +      grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
> > > +      return 0;
> > > +    }
> > > +
> > > +  while (offset < file_size)
> > > +    {
> > > +      grub_off_t maxsize = grub_min (blocksz, file_size - offset);
> > > +      struct grub_erofs_dirent *de = (void *)buf, *end;
> > > +      grub_uint16_t nameoff;
> > > +
> > > +      err = grub_erofs_read_raw_data (dir, buf, maxsize, offset, NULL);
> > > +      if (err)
> > > +        goto not_found;
> > > +
> > > +      nameoff = grub_le_to_cpu16 (de->nameoff);
> > > +      if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > 
> > > blocksz)
> > > +        {
> > > +          grub_error (GRUB_ERR_BAD_FS,
> > > +                      "invalid de[0].nameoff %u @ inode %" 
> > > PRIuGRUB_UINT64_T,
> > > +                      nameoff, dir->ino);
> > > +          goto not_found;
> > > +        }
> > > +
> > > +      end = (struct grub_erofs_dirent *)((char *)de + nameoff);
> > > +      while (de < end)
> > > +        {
> > > +          struct grub_fshelp_node *fdiro;
> > > +          enum grub_fshelp_filetype type;
> > > +          char filename[EROFS_NAME_LEN + 1];
> > > +          unsigned int de_namelen;
> > > +          const char *de_name;
> > > +
> > > +          fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
> > > +          if (!fdiro)
> > > +            {
> > > +              grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
> > > +              goto not_found;
> > > +            }
> > > +
> > > +          fdiro->data = dir->data;
> > > +          fdiro->ino = grub_le_to_cpu64 (de->nid);
> > > +          fdiro->inode_read = false;
> > > +
> > > +          nameoff = grub_le_to_cpu16 (de->nameoff);
> > > +          de_name = buf + nameoff;
> > > +          if (de + 1 >= end)
> > > +            de_namelen = grub_strnlen (de_name, maxsize - nameoff);
> > > +          else
> > > +            de_namelen = grub_le_to_cpu16 (de[1].nameoff) - nameoff;
> > > +
> > > +          grub_memcpy (filename, de_name, de_namelen);
> > > +          filename[de_namelen] = '\0';
> > > +
> > > +          switch (grub_le_to_cpu16 (de->file_type))
> > > +            {
> > > +            case EROFS_FT_REG_FILE:
> > > +            case EROFS_FT_BLKDEV:
> > > +            case EROFS_FT_CHRDEV:
> > > +            case EROFS_FT_FIFO:
> > > +            case EROFS_FT_SOCK:
> > > +              type = GRUB_FSHELP_REG;
> > > +              break;
> > > +            case EROFS_FT_DIR:
> > > +              type = GRUB_FSHELP_DIR;
> > > +              break;
> > > +            case EROFS_FT_SYMLINK:
> > > +              type = GRUB_FSHELP_SYMLINK;
> > > +              break;
> > > +            case EROFS_FT_UNKNOWN:
> > > +            default:
> > > +              type = GRUB_FSHELP_UNKNOWN;
> > > +              break;
> > > +            }
> > > +
> > > +          if (hook (filename, type, fdiro, hook_data))
> > > +            {
> > > +              grub_free (buf);
> > > +              return 1;
> > > +            }
> > > +
> > > +          ++de;
> > > +        }
> > > +
> > > +      offset += maxsize;
> > > +    }
> > > +
> > > +not_found:
> > > +  grub_free (buf);
> > > +  return 0;
> > > +}
> > > +
> > > +static char *
> > > +grub_erofs_read_symlink (grub_fshelp_node_t node) {
> > > +  char *symlink;
> > > +  grub_size_t sz;
> > > +
> > > +  if (!node->inode_read)
> > > +    {
> > > +      grub_erofs_read_inode (node->data, node);
> > > +      if (grub_errno)
> > > +        {
> > > +          return NULL;
> > > +        }
> > > +    }
> > > +
> > > +  if (grub_add (erofs_inode_file_size (node), 1, &sz))
> > > +    {
> > > +      grub_error (GRUB_ERR_OUT_OF_RANGE, N_ ("overflow is detected"));
> > > +      return NULL;
> > > +    }
> > > +
> > > +  symlink = grub_malloc (sz);
> > > +  if (!symlink)
> > > +    return NULL;
> > > +
> > > +  grub_erofs_read_raw_data (node, symlink, sz - 1, 0, NULL);  if
> > > + (grub_errno)
> > > +    {
> > > +      grub_free (symlink);
> > > +      return NULL;
> > > +    }
> > > +
> > > +  symlink[sz - 1] = '\0';
> > > +  return symlink;
> > > +}
> > > +
> > > +static struct grub_erofs_data *
> > > +grub_erofs_mount (grub_disk_t disk, bool read_root) {
> > > +  struct grub_erofs_super sb;
> > > +  grub_err_t err;
> > > +  struct grub_erofs_data *data;
> > > +  grub_uint32_t feature;
> > > +
> > > +  err = grub_disk_read (disk, EROFS_SUPER_OFFSET >>
> > GRUB_DISK_SECTOR_BITS, 0,
> > > +                        sizeof (sb), &sb);  if (grub_errno ==
> > > + GRUB_ERR_OUT_OF_RANGE)
> > > +    grub_error (GRUB_ERR_BAD_FS, "not a valid erofs filesystem");  if
> > > + (err)
> > > +    return NULL;
> > > +  if (sb.magic != grub_cpu_to_le32_compile_time (EROFS_MAGIC))
> > > +    {
> > > +      grub_error (GRUB_ERR_BAD_FS, "not a valid erofs filesystem");
> > > +      return NULL;
> > > +    }
> > > +
> > > +  feature = grub_le_to_cpu32 (sb.feature_incompat);  if (feature &
> > > + ~EROFS_ALL_FEATURE_INCOMPAT)
> > > +    {
> > > +      grub_error (GRUB_ERR_BAD_FS, "unsupported features: 0x%x",
> > > +                  feature & ~EROFS_ALL_FEATURE_INCOMPAT);
> > > +      return NULL;
> > > +    }
> > > +
> > > +  data = grub_malloc (sizeof (*data));  if (!data)
> > > +    {
> > > +      grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
> > > +      return NULL;
> > > +    }
> > > +
> > > +  data->disk = disk;
> > > +  data->sb = sb;
> > > +
> > > +  if (read_root)
> > > +    {
> > > +      data->inode.data = data;
> > > +      data->inode.ino = grub_le_to_cpu16 (sb.root_nid);
> > > +      err = grub_erofs_read_inode (data, &data->inode);
> > > +      if (err)
> > > +        {
> > > +          grub_free (data);
> > > +          return NULL;
> > > +        }
> > > +    }
> > > +
> > > +  return data;
> > > +}
> > > +
> > > +/* Context for grub_erofs_dir. */
> > > +struct grub_erofs_dir_ctx
> > > +{
> > > +  grub_fs_dir_hook_t hook;
> > > +  void *hook_data;
> > > +  struct grub_erofs_data *data;
> > > +};
> > > +
> > > +/* Helper for grub_erofs_dir. */
> > > +static int
> > > +grub_erofs_dir_iter (const char *filename, enum grub_fshelp_filetype
> > filetype,
> > > +                     grub_fshelp_node_t node, void *data) {
> > > +  struct grub_erofs_dir_ctx *ctx = data;
> > > +  struct grub_dirhook_info info;
> > > +
> > > +  grub_memset (&info, 0, sizeof (info));  if (!node->inode_read)
> > > +    {
> > > +      grub_erofs_read_inode (ctx->data, node);
> > > +      grub_errno = GRUB_ERR_NONE;
> > > +    }
> > > +
> > > +  if (node->inode_read)
> > > +    {
> > > +      info.mtimeset = 1;
> > > +      info.mtime = erofs_inode_mtime (node);
> > > +    }
> > > +
> > > +  info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
> > > +  grub_free (node);
> > > +  return ctx->hook (filename, &info, ctx->hook_data); }
> > > +
> > > +static grub_err_t
> > > +grub_erofs_dir (grub_device_t device, const char *path,
> > grub_fs_dir_hook_t hook,
> > > +                void *hook_data)
> > > +{
> > > +  grub_fshelp_node_t fdiro = NULL;
> > > +  struct grub_erofs_dir_ctx ctx = {
> > > +      .hook = hook,
> > > +      .hook_data = hook_data,
> > > +  };
> > > +
> > > +  ctx.data = grub_erofs_mount (device->disk, true);  if (!ctx.data)
> > > +    goto fail;
> > > +
> > > +  grub_fshelp_find_file (path, &ctx.data->inode, &fdiro,
> > grub_erofs_iterate_dir,
> > > +                         grub_erofs_read_symlink, GRUB_FSHELP_DIR);
> > > + if (grub_errno)
> > > +    goto fail;
> > > +
> > > +  grub_erofs_iterate_dir (fdiro, grub_erofs_dir_iter, &ctx);
> > > +
> > > +fail:
> > > +  if (fdiro != &ctx.data->inode)
> > > +    grub_free (fdiro);
> > > +  grub_free (ctx.data);
> > > +
> > > +  return grub_errno;
> > > +}
> > > +
> > > +static grub_err_t
> > > +grub_erofs_open (grub_file_t file, const char *name) {
> > > +  struct grub_erofs_data *data;
> > > +  struct grub_fshelp_node *fdiro = 0;
> > > +  grub_err_t err;
> > > +
> > > +  data = grub_erofs_mount (file->device->disk, true);  if (!data)
> > > +    {
> > > +      err = grub_errno;
> > > +      goto fail;
> > > +    }
> > > +
> > > +  err =
> > > +      grub_fshelp_find_file (name, &data->inode, &fdiro,
> > grub_erofs_iterate_dir,
> > > +                             grub_erofs_read_symlink,
> > > + GRUB_FSHELP_REG);  if (err)
> > > +    goto fail;
> > > +
> > > +  if (!fdiro->inode_read)
> > > +    {
> > > +      err = grub_erofs_read_inode (data, fdiro);
> > > +      if (err)
> > > +        goto fail;
> > > +    }
> > > +
> > > +  grub_memcpy (&data->inode, fdiro, sizeof (*fdiro));  grub_free
> > > + (fdiro);
> > > +
> > > +  file->data = data;
> > > +  file->size = erofs_inode_file_size (&data->inode);
> > > +
> > > +  return GRUB_ERR_NONE;
> > > +
> > > +fail:
> > > +  if (fdiro != &data->inode)
> > > +    grub_free (fdiro);
> > > +  grub_free (data);
> > > +
> > > +  return err;
> > > +}
> > > +
> > > +static grub_ssize_t
> > > +grub_erofs_read (grub_file_t file, char *buf, grub_size_t len) {
> > > +  struct grub_erofs_data *data = file->data;
> > > +  struct grub_fshelp_node *inode = &data->inode;
> > > +  grub_off_t off = file->offset, ret = 0;
> > > +  grub_off_t file_size;
> > > +
> > > +  if (!inode->inode_read)
> > > +    {
> > > +      grub_erofs_read_inode (data, inode);
> > > +      if (grub_errno)
> > > +        {
> > > +          ret = 0;
> > > +          grub_error (GRUB_ERR_IO, "cannot read @ inode %"
> > PRIuGRUB_UINT64_T,
> > > +                      inode->ino);
> > > +          goto end;
> > > +        }
> > > +    }
> > > +
> > > +  file_size = erofs_inode_file_size (inode);
> > > +
> > > +  if (off >= file_size)
> > > +    goto end;
> > > +
> > > +  if (off + len > file_size)
> > > +    len = file_size - off;
> > > +
> > > +  grub_erofs_read_raw_data (inode, buf, len, off, &ret);  if
> > > + (grub_errno)
> > > +    {
> > > +      ret = 0;
> > > +      grub_error (GRUB_ERR_IO, "cannot read file @ inode %"
> > PRIuGRUB_UINT64_T,
> > > +                  inode->ino);
> > > +      goto end;
> > > +    }
> > > +
> > > +end:
> > > +  return ret;
> > > +}
> > > +
> > > +static grub_err_t
> > > +grub_erofs_close (grub_file_t file)
> > > +{
> > > +  grub_free (file->data);
> > > +
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +static grub_err_t
> > > +grub_erofs_uuid (grub_device_t device, char **uuid) {
> > > +  struct grub_erofs_data *data = grub_erofs_mount (device->disk,
> > > +false);
> > 
> > This should probably be changed to the following so that we don't return a
> > previous error.
> 
> I overlooked that. Thanks.
> 
> >   struct grub_erofs_data *data;
> > 
> >   grub_errno = GRUB_ERR_NONE;
> >   data = grub_erofs_mount (device->disk, false);
> > 
> > > +
> > > +  if (data)
> > > +    *uuid = grub_xasprintf (
> > > +        "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-
> > %02x%02x%02x%02x%02x%"
> > > +        "02x",
> > > +        data->sb.uuid[0], data->sb.uuid[1], data->sb.uuid[2], data-
> > >sb.uuid[3],
> > > +        data->sb.uuid[4], data->sb.uuid[5], data->sb.uuid[6], data-
> > >sb.uuid[7],
> > > +        data->sb.uuid[8], data->sb.uuid[9], data->sb.uuid[10],
> > > +        data->sb.uuid[11], data->sb.uuid[12], data->sb.uuid[13],
> > > +        data->sb.uuid[14], data->sb.uuid[15]);
> > 
> > I want to point out that grub_xasprintf can fail and not set grub_errno,
> > namely when calling grub_malloc. In this case this function *should not*
> > return GRUB_ERR_NONE (but likely will and if it doesn't it will be from some
> > previous failure unrelated to this function). I consider this a bug in
> > grub_xasprintf, so this ideally is correct. I think I'll send a patch for 
> > this.
> > 
> > Glenn
> 
> Thanks for the reminder. I think the code can be left unchanged here.
> 
> 
> Thanks, 
> Yifan Zhao
> 
> 
> 
> > > +  else
> > > +    *uuid = NULL;
> > > +
> > > +  grub_free (data);
> > > +
> > > +  return grub_errno;
> > > +}
> > > +
> > > +static grub_err_t
> > > +grub_erofs_label (grub_device_t device, char **label) {
> > > +  struct grub_erofs_data *data = grub_erofs_mount (device->disk,
> > > +false);
> > > +
> > > +  if (data)
> > > +    *label = grub_strndup ((char *)data->sb.volume_name,
> > > +                           sizeof (data->sb.volume_name));  else
> > > +    *label = NULL;
> > > +
> > > +  grub_free (data);
> > > +
> > > +  return grub_errno;
> > > +}
> > > +
> > > +static grub_err_t
> > > +grub_erofs_mtime (grub_device_t device, grub_int64_t *tm) {
> > > +  struct grub_erofs_data *data = grub_erofs_mount (device->disk,
> > > +false);
> > > +
> > > +  if (!data)
> > > +    *tm = 0;
> > > +  else
> > > +    *tm = grub_le_to_cpu64 (data->sb.build_time);
> > > +
> > > +  grub_free (data);
> > > +
> > > +  return grub_errno;
> > > +}
> > > +
> > > +static struct grub_fs grub_erofs_fs = {
> > > +    .name = "erofs",
> > > +    .fs_dir = grub_erofs_dir,
> > > +    .fs_open = grub_erofs_open,
> > > +    .fs_read = grub_erofs_read,
> > > +    .fs_close = grub_erofs_close,
> > > +    .fs_uuid = grub_erofs_uuid,
> > > +    .fs_label = grub_erofs_label,
> > > +    .fs_mtime = grub_erofs_mtime,
> > > +#ifdef GRUB_UTIL
> > > +    .reserved_first_sector = 1,
> > > +    .blocklist_install = 0,
> > > +#endif
> > > +    .next = 0,
> > > +};
> > > +
> > > +GRUB_MOD_INIT (erofs)
> > > +{
> > > +  grub_fs_register (&grub_erofs_fs);
> > > +}
> > > +
> > > +GRUB_MOD_FINI (erofs)
> > > +{
> > > +  grub_fs_unregister (&grub_erofs_fs); }
> > > \ No newline at end of file
> > > diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c index
> > > 2890aad49..66cbb3c5c 100644
> > > --- a/grub-core/kern/misc.c
> > > +++ b/grub-core/kern/misc.c
> > > @@ -594,6 +594,20 @@ grub_strlen (const char *s)
> > >    return p - s;
> > >  }
> > >
> > > +grub_size_t
> > > +grub_strnlen (const char *s, grub_size_t n) {
> > > +  const char *p = s;
> > > +
> > > +  if (n == 0)
> > > +    return 0;
> > > +
> > > +  while (*p && n--)
> > > +    p++;
> > > +
> > > +  return p - s;
> > > +}
> > > +
> > >  static inline void
> > >  grub_reverse (char *str)
> > >  {
> > > diff --git a/include/grub/misc.h b/include/grub/misc.h index
> > > 1b35a167f..eb4aa55c1 100644
> > > --- a/include/grub/misc.h
> > > +++ b/include/grub/misc.h
> > > @@ -335,6 +335,7 @@ char *EXPORT_FUNC(grub_strdup) (const char *s)
> > > WARN_UNUSED_RESULT;  char *EXPORT_FUNC(grub_strndup) (const char
> > *s,
> > > grub_size_t n) WARN_UNUSED_RESULT;  void
> > *EXPORT_FUNC(grub_memset)
> > > (void *s, int c, grub_size_t n);  grub_size_t EXPORT_FUNC(grub_strlen)
> > > (const char *s) WARN_UNUSED_RESULT;
> > > +grub_size_t EXPORT_FUNC(grub_strnlen) (const char *s, grub_size_t n)
> > > +WARN_UNUSED_RESULT;
> > >
> > >  /* Replace all `ch' characters of `input' with `with' and copy the
> > >     result into `output'; return EOS address of `output'. */
> 

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to