[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v5 0/2] Introduce EROFS support
From: |
Yifan Zhao |
Subject: |
[PATCH v5 0/2] Introduce EROFS support |
Date: |
Mon, 4 Mar 2024 01:15:53 +0800 |
EROFS [1] is a lightweight read-only filesystem designed for performance
which has already been shipped in most Linux distributions as well as widely
used in several scenarios, such as Android system partitions, container
images, and rootfs for embedded devices.
This patch brings EROFS uncompressed support together with related tests.
Now, it's possible to boot directly through GRUB with an EROFS rootfs.
EROFS compressed files will be supported later since it has more work to
polish.
[1] https://erofs.docs.kernel.org
changelog since v4:
- correct the order of 'erofs-utils' in INSTALL
- fix format and alignment issue of #define
- use #define instead of enum for some constants
- fix incorrect usage of grub_off_t, use grub_uint64_t instead
- drop inline keyword for some functions
- 'if (err)' -> 'if (err != GRUB_ERR_NONE)'
- do not split lines slightly over 80 characters
- drop 'grub_' prefix for local functions in erofs module
- use safe math (and add bound check) for risky math operations
- other variable name and style changes according to Daniel's review
This interdiff shows the changes between v5 and v4 for easier review. In
addition, another interdiff between v4 and v2 (previous RVB version) is
provided to Glenn for reference.
Yifan Zhao (2):
fs/erofs: Add support for EROFS
fs/erofs: Add tests for EROFS in grub-fs-tester
.gitignore | 1 +
INSTALL | 8 +-
Makefile.util.def | 7 +
docs/grub.texi | 3 +-
grub-core/Makefile.core.def | 5 +
grub-core/fs/erofs.c | 978 +++++++++++++++++++++++++++++++++++
grub-core/kern/misc.c | 14 +
include/grub/misc.h | 1 +
tests/erofs_test.in | 20 +
tests/util/grub-fs-tester.in | 32 +-
10 files changed, 1057 insertions(+), 12 deletions(-)
create mode 100644 grub-core/fs/erofs.c
create mode 100644 tests/erofs_test.in
Interdiff against v4:
diff --git a/INSTALL b/INSTALL
index 545015ba2..84030c9f4 100644
--- a/INSTALL
+++ b/INSTALL
@@ -83,7 +83,7 @@ Prerequisites for make-check:
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, erofs-utils, e2fsprogs, exfat-utils, f2fs-tools,
+ - btrfs-progs, dosfstools, e2fsprogs, erofs-utils, exfat-utils, f2fs-tools,
genromfs, hfsprogs, jfsutils, nilfs-tools, ntfs-3g, reiserfsprogs,
squashfs-tools, reiserfsprogs, udftools, xfsprogs, zfs-fuse
- exfat-fuse, if not using the exfat kernel module
diff --git a/grub-core/fs/erofs.c b/grub-core/fs/erofs.c
index de57aaa5e..34f16ba20 100644
--- a/grub-core/fs/erofs.c
+++ b/grub-core/fs/erofs.c
@@ -1,7 +1,7 @@
/* erofs.c - Enhanced Read-Only File System */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2023 Free Software Foundation, Inc.
+ * Copyright (C) 2024 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
@@ -30,12 +30,12 @@
GRUB_MOD_LICENSE ("GPLv3+");
-#define EROFS_SUPER_OFFSET (1024)
+#define EROFS_SUPER_OFFSET 1024
#define EROFS_MAGIC 0xE0F5E1E2
-#define EROFS_ISLOTBITS (5)
+#define EROFS_ISLOTBITS 5
#define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE 0x00000004
-#define EROFS_ALL_FEATURE_INCOMPAT (EROFS_FEATURE_INCOMPAT_CHUNKED_FILE)
+#define EROFS_ALL_FEATURE_INCOMPAT
EROFS_FEATURE_INCOMPAT_CHUNKED_FILE
struct grub_erofs_super
{
@@ -53,7 +53,7 @@ struct grub_erofs_super
grub_uint32_t blocks;
grub_uint32_t meta_blkaddr;
grub_uint32_t xattr_blkaddr;
- grub_uint8_t uuid[16];
+ grub_packed_guid_t uuid;
grub_uint8_t volume_name[16];
grub_uint32_t feature_incompat;
@@ -75,15 +75,11 @@ struct grub_erofs_super
#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_INODE_FLAT_PLAIN 0
+#define EROFS_INODE_COMPRESSED_FULL 1
+#define EROFS_INODE_FLAT_INLINE 2
+#define EROFS_INODE_COMPRESSED_COMPACT 3
+#define EROFS_INODE_CHUNK_BASED 4
#define EROFS_I_VERSION_MASKS 0x01
#define EROFS_I_DATALAYOUT_MASKS 0x07
@@ -101,8 +97,11 @@ struct grub_erofs_inode_chunk_info
#define EROFS_CHUNK_FORMAT_INDEXES 0x0020
#define EROFS_BLOCK_MAP_ENTRY_SIZE 4
+#define EROFS_MAP_MAPPED 0x02
-#define EROFS_NULL_ADDR -1
+#define EROFS_NULL_ADDR 1
+#define EROFS_NAME_LEN 255
+#define EROFS_MAX_LOG2_BLOCK_SIZE 16
struct grub_erofs_inode_chunk_index
{
@@ -160,20 +159,14 @@ struct grub_erofs_inode_extended
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
+#define EROFS_FT_UNKNOWN 0
+#define EROFS_FT_REG_FILE 1
+#define EROFS_FT_DIR 2
+#define EROFS_FT_CHRDEV 3
+#define EROFS_FT_BLKDEV 4
+#define EROFS_FT_FIFO 5
+#define EROFS_FT_SOCK 6
+#define EROFS_FT_SYMLINK 7
struct grub_erofs_dirent
{
@@ -183,12 +176,12 @@ struct grub_erofs_dirent
grub_uint8_t reserved;
} GRUB_PACKED;
-#define EROFS_MAP_MAPPED 0x02
-
struct grub_erofs_map_blocks
{
- grub_off_t m_pa, m_la;
- grub_off_t m_plen, m_llen;
+ grub_uint64_t m_pa;
+ grub_uint64_t m_la;
+ grub_uint64_t m_plen;
+ grub_uint64_t m_llen;
grub_uint32_t m_flags;
};
@@ -210,7 +203,7 @@ struct grub_fshelp_node
grub_uint8_t inode_datalayout;
/* if the inode has been read into memory? */
- bool inode_read;
+ bool inode_loaded;
};
struct grub_erofs_data
@@ -221,19 +214,18 @@ struct grub_erofs_data
struct grub_fshelp_node inode;
};
-#define erofs_blocksz(data) (1u << data->sb.log2_blksz)
+#define erofs_blocksz(data) (((grub_uint32_t) 1) << data->sb.log2_blksz)
-static inline grub_uint64_t
+static 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->log2_blksz) +
- (node->ino << EROFS_ISLOTBITS);
+ return (grub_le_to_cpu32 (sb->meta_blkaddr) << sb->log2_blksz) + (node->ino
<< EROFS_ISLOTBITS);
}
static grub_err_t
-grub_erofs_read_inode (struct grub_erofs_data *data, grub_fshelp_node_t node)
+erofs_read_inode (struct grub_erofs_data *data, grub_fshelp_node_t node)
{
struct grub_erofs_inode_compact *dic;
grub_err_t err;
@@ -244,13 +236,11 @@ grub_erofs_read_inode (struct grub_erofs_data *data,
grub_fshelp_node_t node)
err = grub_disk_read (data->disk, addr >> GRUB_DISK_SECTOR_BITS,
addr & (GRUB_DISK_SECTOR_SIZE - 1),
sizeof (struct grub_erofs_inode_compact), dic);
- if (err)
+ if (err != GRUB_ERR_NONE)
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;
+ 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)
{
@@ -259,26 +249,24 @@ grub_erofs_read_inode (struct grub_erofs_data *data,
grub_fshelp_node_t node)
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),
+ sizeof (struct grub_erofs_inode_extended) - sizeof (struct
grub_erofs_inode_compact),
(char *) dic + sizeof (struct grub_erofs_inode_compact));
- if (err)
+ if (err != GRUB_ERR_NONE)
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,
+ return grub_error (GRUB_ERR_BAD_FS, "invalid type %u @ inode %"
PRIuGRUB_UINT64_T,
node->inode_type, node->ino);
}
- node->inode_read = true;
+ node->inode_loaded = true;
return 0;
}
-static inline grub_uint64_t
+static grub_uint64_t
erofs_inode_size (grub_fshelp_node_t node)
{
return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
@@ -286,28 +274,28 @@ erofs_inode_size (grub_fshelp_node_t node)
: sizeof (struct grub_erofs_inode_extended);
}
-static inline grub_uint64_t
+static 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;
+ 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
+static 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;
+ if (cnt == 0)
+ return 0;
+
+ return sizeof (struct grub_erofs_xattr_ibody_header) + (cnt - 1) * sizeof
(grub_uint32_t);
}
-static inline grub_uint64_t
+static grub_uint64_t
erofs_inode_mtime (grub_fshelp_node_t node)
{
return node->inode_type == EROFS_INODE_LAYOUT_COMPACT
@@ -316,31 +304,35 @@ erofs_inode_mtime (grub_fshelp_node_t node)
}
static grub_err_t
-grub_erofs_map_blocks_flatmode (grub_fshelp_node_t node,
+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_uint64_t nblocks, lastblk, file_size;
+ bool tailendpacking = (node->inode_datalayout == EROFS_INODE_FLAT_INLINE);
grub_uint32_t blocksz = erofs_blocksz (node->data);
file_size = erofs_inode_file_size (node);
nblocks = (file_size + blocksz - 1) >> node->data->sb.log2_blksz;
- lastblk = nblocks - tailendpacking;
+ lastblk = nblocks - (tailendpacking ? 1 : 0);
map->m_flags = EROFS_MAP_MAPPED;
if (map->m_la < (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;
+ if (grub_mul (grub_le_to_cpu32 (node->inode.i_u.raw_blkaddr), blocksz,
&map->m_pa) ||
+ grub_add (map->m_pa, map->m_la, &map->m_pa))
+ return GRUB_ERR_OUT_OF_RANGE;
+ if (grub_sub (lastblk * blocksz, map->m_la, &map->m_plen))
+ return GRUB_ERR_OUT_OF_RANGE;
}
else if (tailendpacking)
{
- map->m_pa = erofs_iloc (node) + erofs_inode_size (node) +
- erofs_inode_xattr_ibody_size (node) + (map->m_la % blocksz);
- map->m_plen = file_size - map->m_la;
+ if (grub_add (erofs_iloc (node), erofs_inode_size (node), &map->m_pa) ||
+ grub_add (map->m_pa, erofs_inode_xattr_ibody_size (node), &map->m_pa)
||
+ grub_add (map->m_pa, map->m_la % blocksz, &map->m_pa))
+ return GRUB_ERR_OUT_OF_RANGE;
+ if (grub_sub (file_size, map->m_la, &map->m_plen))
+ return GRUB_ERR_OUT_OF_RANGE;
if (((map->m_pa % blocksz) + map->m_plen) > blocksz)
return grub_error (
@@ -359,12 +351,11 @@ grub_erofs_map_blocks_flatmode (grub_fshelp_node_t node,
}
static grub_err_t
-grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
+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_uint64_t unit, pos, chunknr;
grub_uint8_t chunkbits;
grub_err_t err;
@@ -373,19 +364,26 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
else
unit = EROFS_BLOCK_MAP_ENTRY_SIZE;
- chunkbits = node->data->sb.log2_blksz +
- (chunk_format & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
+ chunkbits = node->data->sb.log2_blksz + (chunk_format &
EROFS_CHUNK_FORMAT_BLKBITS_MASK);
+ if (chunkbits > 64)
+ return grub_error (GRUB_ERR_BAD_FS, "invalid chunkbits %u @ inode %"
PRIuGRUB_UINT64_T,
+ chunkbits, node->ino);
chunknr = map->m_la >> chunkbits;
- pos = ALIGN_UP (erofs_iloc (node) + erofs_inode_size (node) +
- erofs_inode_xattr_ibody_size (node),
- unit);
- pos += chunknr * unit;
+
+ if (grub_add (erofs_iloc (node), erofs_inode_size (node), &pos) ||
+ grub_add (pos, erofs_inode_xattr_ibody_size (node), &pos))
+ return GRUB_ERR_OUT_OF_RANGE;
+ pos = ALIGN_UP (pos, unit);
+ if (grub_add (pos, chunknr * unit, &pos))
+ return GRUB_ERR_OUT_OF_RANGE;
map->m_la = chunknr << chunkbits;
- map->m_plen = grub_min (1ULL << chunkbits,
- ALIGN_UP (erofs_inode_file_size (node) - map->m_la,
- erofs_blocksz (node->data)));
+
+ if (grub_sub (erofs_inode_file_size (node), map->m_la, &map->m_plen))
+ return GRUB_ERR_OUT_OF_RANGE;
+ map->m_plen = grub_min (((grub_uint64_t) 1) << chunkbits,
+ ALIGN_UP (map->m_plen, erofs_blocksz (node->data)));
if (chunk_format & EROFS_CHUNK_FORMAT_INDEXES)
{
@@ -394,7 +392,7 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
err = grub_disk_read (node->data->disk, pos >> GRUB_DISK_SECTOR_BITS,
pos & (GRUB_DISK_SECTOR_SIZE - 1), unit, &idx);
- if (err)
+ if (err != GRUB_ERR_NONE)
return err;
blkaddr = grub_le_to_cpu32 (idx.blkaddr);
@@ -414,10 +412,9 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
{
grub_uint32_t blkaddr_le, blkaddr;
- err =
- grub_disk_read (node->data->disk, pos >> GRUB_DISK_SECTOR_BITS,
+ err = grub_disk_read (node->data->disk, pos >> GRUB_DISK_SECTOR_BITS,
pos & (GRUB_DISK_SECTOR_SIZE - 1), unit,
&blkaddr_le);
- if (err)
+ if (err != GRUB_ERR_NONE)
return err;
blkaddr = grub_le_to_cpu32 (blkaddr_le);
@@ -438,8 +435,7 @@ grub_erofs_map_blocks_chunkmode (grub_fshelp_node_t node,
}
static grub_err_t
-grub_erofs_map_blocks (grub_fshelp_node_t node,
- struct grub_erofs_map_blocks *map)
+erofs_map_blocks (grub_fshelp_node_t node, struct grub_erofs_map_blocks *map)
{
if (map->m_la >= erofs_inode_file_size (node))
{
@@ -450,39 +446,38 @@ grub_erofs_map_blocks (grub_fshelp_node_t node,
}
if (node->inode_datalayout != EROFS_INODE_CHUNK_BASED)
- return grub_erofs_map_blocks_flatmode (node, map);
+ return erofs_map_blocks_flatmode (node, map);
else
- return grub_erofs_map_blocks_chunkmode (node, map);
+ return 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)
+erofs_read_raw_data (grub_fshelp_node_t node, char *buf, grub_uint64_t size,
+ grub_uint64_t offset, grub_uint64_t *bytes)
{
- struct grub_erofs_map_blocks map;
+ struct grub_erofs_map_blocks map = {0};
+ grub_uint64_t cur;
grub_err_t err;
if (bytes)
*bytes = 0;
- if (!node->inode_read)
+ if (!node->inode_loaded)
{
- err = grub_erofs_read_inode (node->data, node);
- if (err)
+ err = erofs_read_inode (node->data, node);
+ if (err != GRUB_ERR_NONE)
return err;
}
- grub_memset (&map, 0, sizeof (map));
-
- grub_off_t cur = offset;
+ cur = offset;
while (cur < offset + size)
{
char *const estart = buf + cur - offset;
- grub_off_t eend, moff = 0;
+ grub_uint64_t eend, moff = 0;
map.m_la = cur;
- err = grub_erofs_map_blocks (node, &map);
- if (err)
+ err = erofs_map_blocks (node, &map);
+ if (err != GRUB_ERR_NONE)
return err;
eend = grub_min (offset + size, map.m_la + map.m_llen);
@@ -498,9 +493,9 @@ grub_erofs_read_raw_data (grub_fshelp_node_t node, char
*buf, grub_off_t size,
/* Hole */
grub_memset (estart, 0, eend - cur);
- cur = eend;
if (bytes)
*bytes += eend - cur;
+ cur = eend;
continue;
}
@@ -514,7 +509,7 @@ grub_erofs_read_raw_data (grub_fshelp_node_t node, char
*buf, grub_off_t size,
(map.m_pa + moff) >> GRUB_DISK_SECTOR_BITS,
(map.m_pa + moff) & (GRUB_DISK_SECTOR_SIZE - 1),
eend - map.m_la, estart);
- if (err)
+ if (err != GRUB_ERR_NONE)
return err;
if (bytes)
@@ -527,18 +522,18 @@ grub_erofs_read_raw_data (grub_fshelp_node_t node, char
*buf, grub_off_t size,
}
static int
-grub_erofs_iterate_dir (grub_fshelp_node_t dir,
- grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+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_uint64_t offset = 0, file_size;
grub_uint32_t blocksz = erofs_blocksz (dir->data);
char *buf;
+ grub_err_t err;
- if (!dir->inode_read)
+ if (!dir->inode_loaded)
{
- err = grub_erofs_read_inode (dir->data, dir);
- if (err)
+ err = erofs_read_inode (dir->data, dir);
+ if (err != GRUB_ERR_NONE)
return 0;
}
@@ -552,30 +547,30 @@ grub_erofs_iterate_dir (grub_fshelp_node_t dir,
while (offset < file_size)
{
- grub_off_t maxsize = grub_min (blocksz, file_size - offset);
+ grub_uint64_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)
+ err = erofs_read_raw_data (dir, buf, maxsize, offset, NULL);
+ if (err != GRUB_ERR_NONE)
goto not_found;
nameoff = grub_le_to_cpu16 (de->nameoff);
- if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > blocksz)
+ if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > maxsize)
{
grub_error (GRUB_ERR_BAD_FS,
- "invalid de[0].nameoff %u @ inode %" PRIuGRUB_UINT64_T,
+ "invalid nameoff %u @ inode %" PRIuGRUB_UINT64_T,
nameoff, dir->ino);
goto not_found;
}
- end = (struct grub_erofs_dirent *) ((char *) de + nameoff);
+ end = (struct grub_erofs_dirent *) ((grub_uint8_t *) 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;
+ grub_size_t de_namelen;
const char *de_name;
fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
@@ -587,15 +582,32 @@ grub_erofs_iterate_dir (grub_fshelp_node_t dir,
fdiro->data = dir->data;
fdiro->ino = grub_le_to_cpu64 (de->nid);
- fdiro->inode_read = false;
+ fdiro->inode_loaded = false;
nameoff = grub_le_to_cpu16 (de->nameoff);
+ if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > maxsize)
+ {
+ grub_error (GRUB_ERR_BAD_FS,
+ "invalid nameoff %u @ inode %" PRIuGRUB_UINT64_T,
+ nameoff, dir->ino);
+ goto not_found;
+ }
+
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;
+ if (nameoff + de_namelen > maxsize || de_namelen > EROFS_NAME_LEN)
+ {
+ grub_error (GRUB_ERR_BAD_FS,
+ "invalid de_namelen %" PRIuGRUB_SIZE
+ " @ inode %" PRIuGRUB_UINT64_T,
+ de_namelen, dir->ino);
+ goto not_found;
+ }
+
grub_memcpy (filename, de_name, de_namelen);
filename[de_namelen] = '\0';
@@ -617,7 +629,6 @@ grub_erofs_iterate_dir (grub_fshelp_node_t dir,
case EROFS_FT_UNKNOWN:
default:
type = GRUB_FSHELP_UNKNOWN;
- break;
}
if (hook (filename, type, fdiro, hook_data))
@@ -638,15 +649,16 @@ not_found:
}
static char *
-grub_erofs_read_symlink (grub_fshelp_node_t node)
+erofs_read_symlink (grub_fshelp_node_t node)
{
char *symlink;
grub_size_t sz;
+ grub_err_t err;
- if (!node->inode_read)
+ if (!node->inode_loaded)
{
- grub_erofs_read_inode (node->data, node);
- if (grub_errno)
+ err = erofs_read_inode (node->data, node);
+ if (err != GRUB_ERR_NONE)
return NULL;
}
@@ -660,8 +672,8 @@ grub_erofs_read_symlink (grub_fshelp_node_t node)
if (!symlink)
return NULL;
- grub_erofs_read_raw_data (node, symlink, sz - 1, 0, NULL);
- if (grub_errno)
+ err = erofs_read_raw_data (node, symlink, sz - 1, 0, NULL);
+ if (err != GRUB_ERR_NONE)
{
grub_free (symlink);
return NULL;
@@ -672,7 +684,7 @@ grub_erofs_read_symlink (grub_fshelp_node_t node)
}
static struct grub_erofs_data *
-grub_erofs_mount (grub_disk_t disk, bool read_root)
+erofs_mount (grub_disk_t disk, bool read_root)
{
struct grub_erofs_super sb;
grub_err_t err;
@@ -683,9 +695,10 @@ grub_erofs_mount (grub_disk_t disk, bool read_root)
sizeof (sb), &sb);
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
grub_error (GRUB_ERR_BAD_FS, "not a valid erofs filesystem");
- if (err)
+ if (err != GRUB_ERR_NONE)
return NULL;
- if (sb.magic != grub_cpu_to_le32_compile_time (EROFS_MAGIC))
+ if (sb.magic != grub_cpu_to_le32_compile_time (EROFS_MAGIC) ||
+ grub_le_to_cpu32 (sb.log2_blksz) > EROFS_MAX_LOG2_BLOCK_SIZE)
{
grub_error (GRUB_ERR_BAD_FS, "not a valid erofs filesystem");
return NULL;
@@ -713,8 +726,8 @@ grub_erofs_mount (grub_disk_t disk, bool 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)
+ err = erofs_read_inode (data, &data->inode);
+ if (err != GRUB_ERR_NONE)
{
grub_free (data);
return NULL;
@@ -734,20 +747,19 @@ struct grub_erofs_dir_ctx
/* Helper for grub_erofs_dir. */
static int
-grub_erofs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
+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;
+ struct grub_dirhook_info info = {0};
- grub_memset (&info, 0, sizeof (info));
- if (!node->inode_read)
+ if (!node->inode_loaded)
{
- grub_erofs_read_inode (ctx->data, node);
+ erofs_read_inode (ctx->data, node);
grub_errno = GRUB_ERR_NONE;
}
- if (node->inode_read)
+ if (node->inode_loaded)
{
info.mtimeset = 1;
info.mtime = erofs_inode_mtime (node);
@@ -763,21 +775,22 @@ 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;
+ grub_err_t err;
struct grub_erofs_dir_ctx ctx = {
.hook = hook,
- .hook_data = hook_data,
+ .hook_data = hook_data
};
- ctx.data = grub_erofs_mount (device->disk, true);
+ ctx.data = 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)
+ err = grub_fshelp_find_file (path, &ctx.data->inode, &fdiro,
erofs_iterate_dir,
+ erofs_read_symlink, GRUB_FSHELP_DIR);
+ if (err != GRUB_ERR_NONE)
goto fail;
- grub_erofs_iterate_dir (fdiro, grub_erofs_dir_iter, &ctx);
+ erofs_iterate_dir (fdiro, erofs_dir_iter, &ctx);
fail:
if (fdiro != &ctx.data->inode)
@@ -794,23 +807,22 @@ grub_erofs_open (grub_file_t file, const char *name)
struct grub_fshelp_node *fdiro = 0;
grub_err_t err;
- data = grub_erofs_mount (file->device->disk, true);
+ data = 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)
+ err = grub_fshelp_find_file (name, &data->inode, &fdiro, erofs_iterate_dir,
+ erofs_read_symlink, GRUB_FSHELP_REG);
+ if (err != GRUB_ERR_NONE)
goto fail;
- if (!fdiro->inode_read)
+ if (!fdiro->inode_loaded)
{
- err = grub_erofs_read_inode (data, fdiro);
- if (err)
+ err = erofs_read_inode (data, fdiro);
+ if (err != GRUB_ERR_NONE)
goto fail;
}
@@ -835,39 +847,40 @@ 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;
+ grub_off_t off = file->offset;
+ grub_uint64_t ret = 0, file_size;
+ grub_err_t err;
- if (!inode->inode_read)
+ if (!inode->inode_loaded)
{
- grub_erofs_read_inode (data, inode);
- if (grub_errno)
+ err = erofs_read_inode (data, inode);
+ if (err != GRUB_ERR_NONE)
{
- ret = 0;
- grub_error (GRUB_ERR_IO, "cannot read @ inode %" PRIuGRUB_UINT64_T,
- inode->ino);
- goto end;
+ grub_error (GRUB_ERR_IO, "cannot read @ inode %" PRIuGRUB_UINT64_T,
inode->ino);
+ return -1;
}
}
file_size = erofs_inode_file_size (inode);
- if (off >= file_size)
- goto end;
+ if (off > file_size)
+ {
+ grub_error (GRUB_ERR_IO, "read past EOF @ inode %" PRIuGRUB_UINT64_T,
inode->ino);
+ return -1;
+ }
+ if (off == file_size)
+ return 0;
if (off + len > file_size)
len = file_size - off;
- grub_erofs_read_raw_data (inode, buf, len, off, &ret);
- if (grub_errno)
+ err = erofs_read_raw_data (inode, buf, len, off, &ret);
+ if (err != GRUB_ERR_NONE)
{
- ret = 0;
- grub_error (GRUB_ERR_IO, "cannot read file @ inode %" PRIuGRUB_UINT64_T,
- inode->ino);
- goto end;
+ grub_error (GRUB_ERR_IO, "cannot read file @ inode %" PRIuGRUB_UINT64_T,
inode->ino);
+ return -1;
}
-end:
return ret;
}
@@ -884,24 +897,18 @@ grub_erofs_uuid (grub_device_t device, char **uuid)
{
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]);
- else
+ data = erofs_mount (device->disk, false);
+ if (!data)
+ {
*uuid = NULL;
+ return grub_errno;
+ }
+
+ *uuid = grub_xasprintf ("%pG", &data->sb.uuid);
grub_free (data);
- return grub_errno;
+ return GRUB_ERR_NONE;
}
static grub_err_t
@@ -909,18 +916,20 @@ grub_erofs_label (grub_device_t device, char **label)
{
struct grub_erofs_data *data;
- grub_errno = GRUB_ERR_NONE;
- data = grub_erofs_mount (device->disk, false);
-
- if (data)
- *label = grub_strndup ((char *) data->sb.volume_name,
- sizeof (data->sb.volume_name));
- else
+ data = erofs_mount (device->disk, false);
+ if (!data)
+ {
*label = NULL;
+ return grub_errno;
+ }
+
+ *label = grub_strndup ((char *) data->sb.volume_name, sizeof
(data->sb.volume_name));
+ if (!*label)
+ return grub_errno;
grub_free (data);
- return grub_errno;
+ return GRUB_ERR_NONE;
}
static grub_err_t
@@ -928,17 +937,18 @@ grub_erofs_mtime (grub_device_t device, grub_int64_t *tm)
{
struct grub_erofs_data *data;
- grub_errno = GRUB_ERR_NONE;
- data = grub_erofs_mount (device->disk, false);
-
+ data = erofs_mount (device->disk, false);
if (!data)
+ {
*tm = 0;
- else
+ return grub_errno;
+ }
+
*tm = grub_le_to_cpu64 (data->sb.build_time);
grub_free (data);
- return grub_errno;
+ return GRUB_ERR_NONE;
}
static struct grub_fs grub_erofs_fs = {
--
2.44.0
- [PATCH v5 0/2] Introduce EROFS support,
Yifan Zhao <=