(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
f2fs.c
       1  /*
       2   * Copyright (C) 2013 Alejandro Martinez Ruiz <alex@nowcomputing.com>
       3   *
       4   * This file may be redistributed under the terms of the
       5   * GNU Lesser General Public License
       6   */
       7  
       8  #include <stddef.h>
       9  #include <string.h>
      10  
      11  #include "superblocks.h"
      12  #include "crc32.h"
      13  
      14  #define F2FS_MAGIC		"\x10\x20\xF5\xF2"
      15  #define F2FS_MAGIC_OFF		0
      16  #define F2FS_UUID_SIZE		16
      17  #define F2FS_LABEL_SIZE		512
      18  #define F2FS_SB1_OFF		0x400
      19  #define F2FS_SB1_KBOFF		(F2FS_SB1_OFF >> 10)
      20  #define F2FS_SB2_OFF		0x1400
      21  #define F2FS_SB2_KBOFF		(F2FS_SB2_OFF >> 10)
      22  
      23  struct f2fs_super_block {					/* According to version 1.1 */
      24  /* 0x00 */	uint32_t	magic;				/* Magic Number */
      25  /* 0x04 */	uint16_t	major_ver;			/* Major Version */
      26  /* 0x06 */	uint16_t	minor_ver;			/* Minor Version */
      27  /* 0x08 */	uint32_t	log_sectorsize;			/* log2 sector size in bytes */
      28  /* 0x0C */	uint32_t	log_sectors_per_block;		/* log2 # of sectors per block */
      29  /* 0x10 */	uint32_t	log_blocksize;			/* log2 block size in bytes */
      30  /* 0x14 */	uint32_t	log_blocks_per_seg;		/* log2 # of blocks per segment */
      31  /* 0x18 */	uint32_t	segs_per_sec;			/* # of segments per section */
      32  /* 0x1C */	uint32_t	secs_per_zone;			/* # of sections per zone */
      33  /* 0x20 */	uint32_t	checksum_offset;		/* checksum offset inside super block */
      34  /* 0x24 */	uint64_t	block_count;			/* total # of user blocks */
      35  /* 0x2C */	uint32_t	section_count;			/* total # of sections */
      36  /* 0x30 */	uint32_t	segment_count;			/* total # of segments */
      37  /* 0x34 */	uint32_t	segment_count_ckpt;		/* # of segments for checkpoint */
      38  /* 0x38 */	uint32_t	segment_count_sit;		/* # of segments for SIT */
      39  /* 0x3C */	uint32_t	segment_count_nat;		/* # of segments for NAT */
      40  /* 0x40 */	uint32_t	segment_count_ssa;		/* # of segments for SSA */
      41  /* 0x44 */	uint32_t	segment_count_main;		/* # of segments for main area */
      42  /* 0x48 */	uint32_t	segment0_blkaddr;		/* start block address of segment 0 */
      43  /* 0x4C */	uint32_t	cp_blkaddr;			/* start block address of checkpoint */
      44  /* 0x50 */	uint32_t	sit_blkaddr;			/* start block address of SIT */
      45  /* 0x54 */	uint32_t	nat_blkaddr;			/* start block address of NAT */
      46  /* 0x58 */	uint32_t	ssa_blkaddr;			/* start block address of SSA */
      47  /* 0x5C */	uint32_t	main_blkaddr;			/* start block address of main area */
      48  /* 0x60 */	uint32_t	root_ino;			/* root inode number */
      49  /* 0x64 */	uint32_t	node_ino;			/* node inode number */
      50  /* 0x68 */	uint32_t	meta_ino;			/* meta inode number */
      51  /* 0x6C */	uint8_t		uuid[F2FS_UUID_SIZE];		/* 128-bit uuid for volume */
      52  /* 0x7C */	uint16_t	volume_name[F2FS_LABEL_SIZE];	/* volume name */
      53  #if 0
      54  /* 0x47C */	uint32_t	extension_count;		/* # of extensions below */
      55  /* 0x480 */	uint8_t		extension_list[64][8];		/* extension array */
      56  #endif
      57  } __attribute__((packed));
      58  
      59  static int f2fs_validate_checksum(blkid_probe pr, size_t sb_off,
      60  		const struct f2fs_super_block *sb)
      61  {
      62  	uint32_t csum_off = le32_to_cpu(sb->checksum_offset);
      63  	if (!csum_off)
      64  		return 1;
      65  	if (csum_off % sizeof(uint32_t) != 0)
      66  		return 0;
      67  	if (csum_off + sizeof(uint32_t) > 4096)
      68  		return 0;
      69  
      70  	unsigned char *csum_data = blkid_probe_get_buffer(pr,
      71  			sb_off + csum_off, sizeof(uint32_t));
      72  	if (!csum_data)
      73  		return 0;
      74  
      75  	uint32_t expected = le32_to_cpu(*(uint32_t *) csum_data);
      76  
      77  	unsigned char *csummed = blkid_probe_get_buffer(pr, sb_off, csum_off);
      78  	if (!csummed)
      79  		return 0;
      80  
      81  	uint32_t csum = ul_crc32(0xF2F52010, csummed, csum_off);
      82  
      83  	return blkid_probe_verify_csum(pr, csum, expected);
      84  }
      85  
      86  static int probe_f2fs(blkid_probe pr, const struct blkid_idmag *mag)
      87  {
      88  	struct f2fs_super_block *sb;
      89  	uint16_t vermaj, vermin;
      90  
      91  	sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block);
      92  	if (!sb)
      93  		return errno ? -errno : 1;
      94  
      95  	vermaj = le16_to_cpu(sb->major_ver);
      96  	vermin = le16_to_cpu(sb->minor_ver);
      97  
      98  	/* For version 1.0 we cannot know the correct sb structure */
      99  	if (vermaj == 1 && vermin == 0)
     100  		return 0;
     101  
     102  	if (!f2fs_validate_checksum(pr, mag->kboff << 10, sb))
     103  		return 1;
     104  
     105  	if (*((unsigned char *) sb->volume_name))
     106  		blkid_probe_set_utf8label(pr, (unsigned char *) sb->volume_name,
     107  						sizeof(sb->volume_name),
     108  						UL_ENCODE_UTF16LE);
     109  
     110  	blkid_probe_set_uuid(pr, sb->uuid);
     111  	blkid_probe_sprintf_version(pr, "%u.%u", vermaj, vermin);
     112  	if (le32_to_cpu(sb->log_blocksize) < 32){
     113  		uint32_t blocksize = 1U << le32_to_cpu(sb->log_blocksize);
     114  		blkid_probe_set_fsblocksize(pr, blocksize);
     115  		blkid_probe_set_block_size(pr, blocksize);
     116  		blkid_probe_set_fssize(pr, le64_to_cpu(sb->block_count) * blocksize);
     117  	}
     118  	return 0;
     119  }
     120  
     121  const struct blkid_idinfo f2fs_idinfo =
     122  {
     123  	.name           = "f2fs",
     124  	.usage          = BLKID_USAGE_FILESYSTEM,
     125  	.probefunc      = probe_f2fs,
     126  	.magics         =
     127          {
     128  		{
     129  			.magic = F2FS_MAGIC,
     130  			.len = 4,
     131  			.kboff = F2FS_SB1_KBOFF,
     132  			.sboff = F2FS_MAGIC_OFF
     133  		},
     134  		{ NULL }
     135  	}
     136  };