(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
ext.c
       1  /*
       2   * Copyright (C) 1999, 2001 by Andries Brouwer
       3   * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
       4   * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
       5   *
       6   * This file may be redistributed under the terms of the
       7   * GNU Lesser General Public License.
       8   */
       9  #include <stdio.h>
      10  #include <stdlib.h>
      11  #include <unistd.h>
      12  #include <string.h>
      13  #include <errno.h>
      14  #include <ctype.h>
      15  #include <stdint.h>
      16  #ifdef __linux__
      17  #include <sys/utsname.h>
      18  #endif
      19  #include <time.h>
      20  
      21  #include "superblocks.h"
      22  #include "crc32c.h"
      23  
      24  struct ext2_super_block {
      25  	uint32_t		s_inodes_count;
      26  	uint32_t		s_blocks_count;
      27  	uint32_t		s_r_blocks_count;
      28  	uint32_t		s_free_blocks_count;
      29  	uint32_t		s_free_inodes_count;
      30  	uint32_t		s_first_data_block;
      31  	uint32_t		s_log_block_size;
      32  	uint32_t		s_dummy3[7];
      33  	unsigned char		s_magic[2];
      34  	uint16_t		s_state;
      35  	uint16_t		s_errors;
      36  	uint16_t		s_minor_rev_level;
      37  	uint32_t		s_lastcheck;
      38  	uint32_t		s_checkinterval;
      39  	uint32_t		s_creator_os;
      40  	uint32_t		s_rev_level;
      41  	uint16_t		s_def_resuid;
      42  	uint16_t		s_def_resgid;
      43  	uint32_t		s_first_ino;
      44  	uint16_t		s_inode_size;
      45  	uint16_t		s_block_group_nr;
      46  	uint32_t		s_feature_compat;
      47  	uint32_t		s_feature_incompat;
      48  	uint32_t		s_feature_ro_compat;
      49  	unsigned char		s_uuid[16];
      50  	char			s_volume_name[16];
      51  	char			s_last_mounted[64];
      52  	uint32_t		s_algorithm_usage_bitmap;
      53  	uint8_t			s_prealloc_blocks;
      54  	uint8_t			s_prealloc_dir_blocks;
      55  	uint16_t		s_reserved_gdt_blocks;
      56  	uint8_t			s_journal_uuid[16];
      57  	uint32_t		s_journal_inum;
      58  	uint32_t		s_journal_dev;
      59  	uint32_t		s_last_orphan;
      60  	uint32_t		s_hash_seed[4];
      61  	uint8_t			s_def_hash_version;
      62  	uint8_t			s_jnl_backup_type;
      63  	uint16_t		s_reserved_word_pad;
      64  	uint32_t		s_default_mount_opts;
      65  	uint32_t		s_first_meta_bg;
      66  	uint32_t		s_mkfs_time;
      67  	uint32_t		s_jnl_blocks[17];
      68  	uint32_t		s_blocks_count_hi;
      69  	uint32_t		s_r_blocks_count_hi;
      70  	uint32_t		s_free_blocks_hi;
      71  	uint16_t		s_min_extra_isize;
      72  	uint16_t		s_want_extra_isize;
      73  	uint32_t		s_flags;
      74  	uint16_t		s_raid_stride;
      75  	uint16_t		s_mmp_interval;
      76  	uint64_t		s_mmp_block;
      77  	uint32_t		s_raid_stripe_width;
      78  	uint32_t		s_reserved[162];
      79  	uint32_t		s_checksum;
      80  } __attribute__((packed));
      81  
      82  /* magic string */
      83  #define EXT_SB_MAGIC				"\123\357"
      84  /* supper block offset */
      85  #define EXT_SB_OFF				0x400
      86  /* supper block offset in kB */
      87  #define EXT_SB_KBOFF				(EXT_SB_OFF >> 10)
      88  /* magic string offset within super block */
      89  #define EXT_MAG_OFF				0x38
      90  
      91  
      92  
      93  /* for s_flags */
      94  #define EXT2_FLAGS_TEST_FILESYS		0x0004
      95  
      96  /* for s_feature_compat */
      97  #define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
      98  
      99  /* for s_feature_ro_compat */
     100  #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
     101  #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
     102  #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
     103  #define EXT4_FEATURE_RO_COMPAT_HUGE_FILE	0x0008
     104  #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010
     105  #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK	0x0020
     106  #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE	0x0040
     107  #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM	0x0400
     108  
     109  /* for s_feature_incompat */
     110  #define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
     111  #define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004
     112  #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
     113  #define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
     114  #define EXT4_FEATURE_INCOMPAT_EXTENTS		0x0040 /* extents support */
     115  #define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
     116  #define EXT4_FEATURE_INCOMPAT_MMP		0x0100
     117  #define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
     118  
     119  #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
     120  					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
     121  					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
     122  #define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
     123  					 EXT2_FEATURE_INCOMPAT_META_BG)
     124  #define EXT2_FEATURE_INCOMPAT_UNSUPPORTED	~EXT2_FEATURE_INCOMPAT_SUPP
     125  #define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT2_FEATURE_RO_COMPAT_SUPP
     126  
     127  #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
     128  					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
     129  					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
     130  #define EXT3_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
     131  					 EXT3_FEATURE_INCOMPAT_RECOVER| \
     132  					 EXT2_FEATURE_INCOMPAT_META_BG)
     133  #define EXT3_FEATURE_INCOMPAT_UNSUPPORTED	~EXT3_FEATURE_INCOMPAT_SUPP
     134  #define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT3_FEATURE_RO_COMPAT_SUPP
     135  
     136  /*
     137   * Starting in 2.6.29, ext4 can be used to support filesystems
     138   * without a journal.
     139   */
     140  #define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
     141  
     142  /*
     143   * reads superblock and returns:
     144   *	fc = feature_compat
     145   *	fi = feature_incompat
     146   *	frc = feature_ro_compat
     147   */
     148  static struct ext2_super_block *ext_get_super(
     149  		blkid_probe pr, uint32_t *fc, uint32_t *fi, uint32_t *frc)
     150  {
     151  	struct ext2_super_block *es;
     152  
     153  	es = (struct ext2_super_block *)
     154  			blkid_probe_get_buffer(pr, EXT_SB_OFF, sizeof(struct ext2_super_block));
     155  	if (!es)
     156  		return NULL;
     157  	if (le32_to_cpu(es->s_feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
     158  		uint32_t csum = crc32c(~0, es, offsetof(struct ext2_super_block, s_checksum));
     159  		if (!blkid_probe_verify_csum(pr, csum, le32_to_cpu(es->s_checksum)))
     160  			return NULL;
     161  	}
     162  	if (fc)
     163  		*fc = le32_to_cpu(es->s_feature_compat);
     164  	if (fi)
     165  		*fi = le32_to_cpu(es->s_feature_incompat);
     166  	if (frc)
     167  		*frc = le32_to_cpu(es->s_feature_ro_compat);
     168  
     169  	return es;
     170  }
     171  
     172  static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es)
     173  {
     174  	struct blkid_chain *chn = blkid_probe_get_chain(pr);
     175  	uint32_t s_feature_incompat = le32_to_cpu(es->s_feature_incompat);
     176  
     177  	DBG(PROBE, ul_debug("ext2_sb.compat = %08X:%08X:%08X",
     178  		   le32_to_cpu(es->s_feature_compat),
     179  		   s_feature_incompat,
     180  		   le32_to_cpu(es->s_feature_ro_compat)));
     181  
     182  	if (*es->s_volume_name != '\0')
     183  		blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name,
     184  					sizeof(es->s_volume_name));
     185  	blkid_probe_set_uuid(pr, es->s_uuid);
     186  
     187  	if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
     188  		blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL");
     189  
     190  	if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) &&
     191  	    ((s_feature_incompat & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0))
     192  		blkid_probe_set_value(pr, "SEC_TYPE",
     193  				(unsigned char *) "ext2",
     194  				sizeof("ext2"));
     195  
     196  	blkid_probe_sprintf_version(pr, "%u.%u",
     197  		le32_to_cpu(es->s_rev_level),
     198  		le16_to_cpu(es->s_minor_rev_level));
     199  
     200  	uint32_t block_size = 0;
     201  	if (le32_to_cpu(es->s_log_block_size) < 32){
     202  		block_size = 1024U << le32_to_cpu(es->s_log_block_size);
     203  		blkid_probe_set_fsblocksize(pr, block_size);
     204  		blkid_probe_set_block_size(pr, block_size);
     205  	}
     206  
     207  	uint64_t fslastblock = le32_to_cpu(es->s_blocks_count) |
     208  		((s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ?
     209  		(uint64_t) le32_to_cpu(es->s_blocks_count_hi) << 32 : 0);
     210  	blkid_probe_set_fslastblock(pr, fslastblock);
     211  
     212  	/* The total number of blocks is taken without substraction of overhead
     213  	 * (journal, metadata). The ext4 has non-trivial overhead calculation
     214  	 * viz. ext4_calculate_overhead(). Thefore, the FSSIZE would show number
     215  	 * slightly higher than the real value (for example, calculated via
     216  	 * statfs()).
     217  	 */
     218  	uint64_t fssize = (uint64_t) block_size * le32_to_cpu(es->s_blocks_count);
     219  	blkid_probe_set_fssize(pr, fssize);
     220  }
     221  
     222  
     223  static int probe_jbd(blkid_probe pr,
     224  		const struct blkid_idmag *mag __attribute__((__unused__)))
     225  {
     226  	struct ext2_super_block *es;
     227  	uint32_t fi;
     228  
     229  	es = ext_get_super(pr, NULL, &fi, NULL);
     230  	if (!es)
     231  		return errno ? -errno : 1;
     232  	if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
     233  		return 1;
     234  
     235  	ext_get_info(pr, 2, es);
     236  	blkid_probe_set_uuid_as(pr, es->s_uuid, "LOGUUID");
     237  
     238  	return 0;
     239  }
     240  
     241  static int probe_ext2(blkid_probe pr,
     242  		const struct blkid_idmag *mag __attribute__((__unused__)))
     243  {
     244  	struct ext2_super_block *es;
     245  	uint32_t fc, frc, fi;
     246  
     247  	es = ext_get_super(pr, &fc, &fi, &frc);
     248  	if (!es)
     249  		return errno ? -errno : 1;
     250  
     251  	/* Distinguish between ext3 and ext2 */
     252  	if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
     253  		return 1;
     254  
     255  	/* Any features which ext2 doesn't understand */
     256  	if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
     257  	    (fi  & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
     258  		return 1;
     259  
     260  	ext_get_info(pr, 2, es);
     261  	return 0;
     262  }
     263  
     264  static int probe_ext3(blkid_probe pr,
     265  		const struct blkid_idmag *mag __attribute__((__unused__)))
     266  {
     267  	struct ext2_super_block *es;
     268  	uint32_t fc, frc, fi;
     269  
     270  	es = ext_get_super(pr, &fc, &fi, &frc);
     271  	if (!es)
     272  		return errno ? -errno : 1;
     273  
     274  	/* ext3 requires journal */
     275  	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
     276  		return 1;
     277  
     278  	/* Any features which ext3 doesn't understand */
     279  	if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
     280  	    (fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
     281  		return 1;
     282  
     283  	ext_get_info(pr, 3, es);
     284  	return 0;
     285  }
     286  
     287  
     288  static int probe_ext4dev(blkid_probe pr,
     289  		const struct blkid_idmag *mag __attribute__((__unused__)))
     290  {
     291  	struct ext2_super_block *es;
     292  	uint32_t fc, frc, fi;
     293  
     294  	es = ext_get_super(pr, &fc, &fi, &frc);
     295  	if (!es)
     296  		return errno ? -errno : 1;
     297  
     298  	/* Distinguish from jbd */
     299  	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
     300  		return 1;
     301  
     302  	if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS))
     303  		return 1;
     304  
     305  	ext_get_info(pr, 4, es);
     306  	return 0;
     307  }
     308  
     309  static int probe_ext4(blkid_probe pr,
     310  		const struct blkid_idmag *mag __attribute__((__unused__)))
     311  {
     312  	struct ext2_super_block *es;
     313  	uint32_t fc, frc, fi;
     314  
     315  	es = ext_get_super(pr, &fc, &fi, &frc);
     316  	if (!es)
     317  		return errno ? -errno : 1;
     318  
     319  	/* Distinguish from jbd */
     320  	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
     321  		return 1;
     322  
     323  	/* Ext4 has at least one feature which ext3 doesn't understand */
     324  	if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
     325  	    !(fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
     326  		return 1;
     327  
     328  	/*
     329  	 * If the filesystem is a OK for use by in-development
     330  	 * filesystem code, and ext4dev is supported or ext4 is not
     331  	 * supported, then don't call ourselves ext4, so we can redo
     332  	 * the detection and mark the filesystem as ext4dev.
     333  	 *
     334  	 * If the filesystem is marked as in use by production
     335  	 * filesystem, then it can only be used by ext4 and NOT by
     336  	 * ext4dev.
     337  	 */
     338  	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
     339  		return 1;
     340  
     341  	ext_get_info(pr, 4, es);
     342  	return 0;
     343  }
     344  
     345  #define BLKID_EXT_MAGICS \
     346  	{ \
     347  		{	 \
     348  			.magic = EXT_SB_MAGIC, \
     349  			.len = sizeof(EXT_SB_MAGIC) - 1, \
     350  			.kboff = EXT_SB_KBOFF, \
     351  			.sboff = EXT_MAG_OFF \
     352  		}, \
     353  		{ NULL } \
     354  	}
     355  
     356  const struct blkid_idinfo jbd_idinfo =
     357  {
     358  	.name		= "jbd",
     359  	.usage		= BLKID_USAGE_OTHER,
     360  	.probefunc	= probe_jbd,
     361  	.magics		= BLKID_EXT_MAGICS
     362  };
     363  
     364  const struct blkid_idinfo ext2_idinfo =
     365  {
     366  	.name		= "ext2",
     367  	.usage		= BLKID_USAGE_FILESYSTEM,
     368  	.probefunc	= probe_ext2,
     369  	.magics		= BLKID_EXT_MAGICS
     370  };
     371  
     372  const struct blkid_idinfo ext3_idinfo =
     373  {
     374  	.name		= "ext3",
     375  	.usage		= BLKID_USAGE_FILESYSTEM,
     376  	.probefunc	= probe_ext3,
     377  	.magics		= BLKID_EXT_MAGICS
     378  };
     379  
     380  const struct blkid_idinfo ext4_idinfo =
     381  {
     382  	.name		= "ext4",
     383  	.usage		= BLKID_USAGE_FILESYSTEM,
     384  	.probefunc	= probe_ext4,
     385  	.magics		= BLKID_EXT_MAGICS
     386  };
     387  
     388  const struct blkid_idinfo ext4dev_idinfo =
     389  {
     390  	.name		= "ext4dev",
     391  	.usage		= BLKID_USAGE_FILESYSTEM,
     392  	.probefunc	= probe_ext4dev,
     393  	.magics		= BLKID_EXT_MAGICS
     394  };
     395