(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
erofs.c
       1  /*
       2   * Copyright (C) 2020 Gao Xiang
       3   *
       4   * This file may be redistributed under the terms of the
       5   * GNU Lesser General Public License
       6   *
       7   * https://docs.kernel.org/filesystems/erofs.html
       8   */
       9  #include <stddef.h>
      10  #include <string.h>
      11  
      12  #include "superblocks.h"
      13  #include "crc32c.h"
      14  
      15  #define EROFS_SUPER_OFFSET      1024
      16  #define EROFS_SB_KBOFF		(EROFS_SUPER_OFFSET >> 10)
      17  #define EROFS_FEATURE_SB_CSUM	(1 << 0)
      18  
      19  #define EROFS_SUPER_MAGIC_V1	"\xe2\xe1\xf5\xe0"
      20  #define EROFS_MAGIC_OFF		0
      21  
      22  /* All in little-endian */
      23  struct erofs_super_block {
      24  	uint32_t	magic;
      25  	uint32_t	checksum;
      26  	uint32_t	feature_compat;
      27  	uint8_t		blkszbits;
      28  	uint8_t		reserved;
      29  
      30  	uint16_t	root_nid;
      31  	uint64_t	inos;
      32  
      33  	uint64_t	build_time;
      34  	uint32_t	build_time_nsec;
      35  	uint32_t	blocks;
      36  	uint32_t	meta_blkaddr;
      37  	uint32_t	xattr_blkaddr;
      38  	uint8_t		uuid[16];
      39  	uint8_t		volume_name[16];
      40  	uint32_t	feature_incompat;
      41  	uint8_t		reserved2[44];
      42  } __attribute__((packed));
      43  
      44  static int erofs_verify_checksum(blkid_probe pr, const struct blkid_idmag *mag,
      45  		const struct erofs_super_block *sb)
      46  {
      47  	uint32_t expected, csum;
      48  	size_t csummed_size;
      49  	unsigned char *csummed;
      50  
      51  	if (!(le32_to_cpu(sb->feature_compat) & EROFS_FEATURE_SB_CSUM))
      52  		return 1;
      53  
      54  	expected = le32_to_cpu(sb->checksum);
      55  	csummed_size = (1U << sb->blkszbits) - EROFS_SUPER_OFFSET;
      56  
      57  	csummed = blkid_probe_get_sb_buffer(pr, mag, csummed_size);
      58  	if (!csummed)
      59  		return 0;
      60  
      61  	csum = ul_crc32c_exclude_offset(~0L, csummed, csummed_size,
      62  			                offsetof(struct erofs_super_block, checksum),
      63  					sizeof_member(struct erofs_super_block, checksum));
      64  
      65  	return blkid_probe_verify_csum(pr, csum, expected);
      66  }
      67  
      68  static int probe_erofs(blkid_probe pr, const struct blkid_idmag *mag)
      69  {
      70  	struct erofs_super_block *sb;
      71  
      72  	sb = blkid_probe_get_sb(pr, mag, struct erofs_super_block);
      73  	if (!sb)
      74  		return errno ? -errno : BLKID_PROBE_NONE;
      75  
      76  	/* EROFS is restricted to 4KiB block size */
      77  	if (sb->blkszbits > 31 || (1U << sb->blkszbits) > 4096)
      78  		return BLKID_PROBE_NONE;
      79  
      80  	if (!erofs_verify_checksum(pr, mag, sb))
      81  		return BLKID_PROBE_NONE;
      82  
      83  	if (sb->volume_name[0])
      84  		blkid_probe_set_label(pr, (unsigned char *)sb->volume_name,
      85  				      sizeof(sb->volume_name));
      86  
      87  	blkid_probe_set_uuid(pr, sb->uuid);
      88  	blkid_probe_set_fsblocksize(pr, 1U << sb->blkszbits);
      89  	blkid_probe_set_block_size(pr, 1U << sb->blkszbits);
      90  	blkid_probe_set_fssize(pr, (uint64_t) (1U << sb->blkszbits) * le32_to_cpu(sb->blocks));
      91  
      92  	return BLKID_PROBE_OK;
      93  }
      94  
      95  const struct blkid_idinfo erofs_idinfo =
      96  {
      97  	.name           = "erofs",
      98  	.usage          = BLKID_USAGE_FILESYSTEM,
      99  	.probefunc      = probe_erofs,
     100  	.magics         =
     101          {
     102  		{
     103  			.magic = EROFS_SUPER_MAGIC_V1,
     104  			.len = 4,
     105  			.kboff = EROFS_SB_KBOFF,
     106  			.sboff = EROFS_MAGIC_OFF,
     107  		}, { NULL }
     108  	}
     109  };