Coverage Report

Created: 2025-11-11 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/superblocks/ext.c
Line
Count
Source
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
2.31k
#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
82
#define EXT2_FLAGS_TEST_FILESYS   0x0004
95
96
/* for s_feature_compat */
97
206
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL   0x0004
98
99
/* for s_feature_ro_compat */
100
116
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
101
116
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
102
116
#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
1.68k
#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM  0x0400
108
109
/* for s_feature_incompat */
110
53
#define EXT2_FEATURE_INCOMPAT_FILETYPE    0x0002
111
35
#define EXT3_FEATURE_INCOMPAT_RECOVER   0x0004
112
201
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
113
53
#define EXT2_FEATURE_INCOMPAT_META_BG   0x0010
114
#define EXT4_FEATURE_INCOMPAT_EXTENTS   0x0040 /* extents support */
115
72
#define EXT4_FEATURE_INCOMPAT_64BIT   0x0080
116
#define EXT4_FEATURE_INCOMPAT_MMP   0x0100
117
#define EXT4_FEATURE_INCOMPAT_FLEX_BG   0x0200
118
119
30
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
120
30
           EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
121
30
           EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
122
18
#define EXT2_FEATURE_INCOMPAT_SUPP  (EXT2_FEATURE_INCOMPAT_FILETYPE| \
123
18
           EXT2_FEATURE_INCOMPAT_META_BG)
124
18
#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP
125
30
#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED  ~EXT2_FEATURE_RO_COMPAT_SUPP
126
127
86
#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
128
86
           EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
129
86
           EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
130
35
#define EXT3_FEATURE_INCOMPAT_SUPP  (EXT2_FEATURE_INCOMPAT_FILETYPE| \
131
35
           EXT3_FEATURE_INCOMPAT_RECOVER| \
132
35
           EXT2_FEATURE_INCOMPAT_META_BG)
133
35
#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP
134
86
#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
1.68k
{
151
1.68k
  struct ext2_super_block *es;
152
153
1.68k
  es = (struct ext2_super_block *)
154
1.68k
      blkid_probe_get_buffer(pr, EXT_SB_OFF, sizeof(struct ext2_super_block));
155
1.68k
  if (!es)
156
0
    return NULL;
157
1.68k
  if (le32_to_cpu(es->s_feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
158
635
    uint32_t csum = crc32c(~0, es, offsetof(struct ext2_super_block, s_checksum));
159
    /*
160
     * A read of the superblock can race with other updates to the
161
     * same superblock.  In the unlikely event that this occurs and
162
     * we see a checksum failure, re-read the superblock with
163
     * O_DIRECT to ensure that it's consistent.  If it _still_ fails
164
     * then declare a checksum mismatch.
165
     */
166
635
    if (!blkid_probe_verify_csum(pr, csum, le32_to_cpu(es->s_checksum))) {
167
625
#ifdef O_DIRECT
168
625
      if (blkid_probe_reset_buffers(pr))
169
0
        return NULL;
170
171
625
      es = (struct ext2_super_block *)
172
625
          blkid_probe_get_buffer_direct(pr, EXT_SB_OFF, sizeof(struct ext2_super_block));
173
625
      if (!es)
174
0
        return NULL;
175
176
625
      csum = crc32c(~0, es, offsetof(struct ext2_super_block, s_checksum));
177
625
      if (!blkid_probe_verify_csum(pr, csum, le32_to_cpu(es->s_checksum)))
178
625
        return NULL;
179
#else
180
      return NULL;
181
#endif
182
625
    }
183
1.05k
  } else {
184
    /*
185
     * For legacy fs without checksum, additionally verify the
186
     * block size to reduce false positive. Currently max allowed
187
     * block size is 64KiB (s_log_block_size <= 6), check for 256
188
     * to be more future proof.
189
     */
190
1.05k
    if (le32_to_cpu(es->s_log_block_size) >= 256)
191
725
      return NULL;
192
1.05k
  }
193
335
  if (fc)
194
268
    *fc = le32_to_cpu(es->s_feature_compat);
195
335
  if (fi)
196
335
    *fi = le32_to_cpu(es->s_feature_incompat);
197
335
  if (frc)
198
268
    *frc = le32_to_cpu(es->s_feature_ro_compat);
199
200
335
  return es;
201
1.68k
}
202
203
static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es)
204
72
{
205
72
  struct blkid_chain *chn = blkid_probe_get_chain(pr);
206
72
  uint32_t s_feature_incompat = le32_to_cpu(es->s_feature_incompat);
207
208
72
  DBG(PROBE, ul_debug("ext2_sb.compat = %08X:%08X:%08X",
209
72
       le32_to_cpu(es->s_feature_compat),
210
72
       s_feature_incompat,
211
72
       le32_to_cpu(es->s_feature_ro_compat)));
212
213
72
  if (*es->s_volume_name != '\0')
214
36
    blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name,
215
36
          sizeof(es->s_volume_name));
216
72
  blkid_probe_set_uuid(pr, es->s_uuid);
217
218
72
  if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
219
40
    blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL");
220
221
72
  if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) &&
222
0
      ((s_feature_incompat & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0))
223
0
    blkid_probe_set_value(pr, "SEC_TYPE",
224
0
        (unsigned char *) "ext2",
225
0
        sizeof("ext2"));
226
227
72
  blkid_probe_sprintf_version(pr, "%u.%u",
228
72
    le32_to_cpu(es->s_rev_level),
229
72
    le16_to_cpu(es->s_minor_rev_level));
230
231
72
  uint32_t block_size = 0;
232
72
  if (le32_to_cpu(es->s_log_block_size) < 32){
233
60
    block_size = 1024U << le32_to_cpu(es->s_log_block_size);
234
60
    blkid_probe_set_fsblocksize(pr, block_size);
235
60
    blkid_probe_set_block_size(pr, block_size);
236
60
  }
237
238
72
  uint64_t fslastblock = le32_to_cpu(es->s_blocks_count) |
239
72
    ((s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ?
240
61
    (uint64_t) le32_to_cpu(es->s_blocks_count_hi) << 32 : 0);
241
72
  blkid_probe_set_fslastblock(pr, fslastblock);
242
243
  /* The total number of blocks is taken without subtraction of overhead
244
   * (journal, metadata). The ext4 has non-trivial overhead calculation
245
   * viz. ext4_calculate_overhead(). Therefore, the FSSIZE would show number
246
   * slightly higher than the real value (for example, calculated via
247
   * statfs()).
248
   */
249
72
  uint64_t fssize = (uint64_t) block_size * le32_to_cpu(es->s_blocks_count);
250
72
  blkid_probe_set_fssize(pr, fssize);
251
72
}
252
253
254
static int probe_jbd(blkid_probe pr,
255
    const struct blkid_idmag *mag __attribute__((__unused__)))
256
337
{
257
337
  struct ext2_super_block *es;
258
337
  uint32_t fi;
259
260
337
  es = ext_get_super(pr, NULL, &fi, NULL);
261
337
  if (!es)
262
270
    return errno ? -errno : 1;
263
67
  if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
264
49
    return 1;
265
266
18
  ext_get_info(pr, 2, es);
267
18
  blkid_probe_set_uuid_as(pr, es->s_uuid, "LOGUUID");
268
269
18
  return 0;
270
67
}
271
272
static int probe_ext2(blkid_probe pr,
273
    const struct blkid_idmag *mag __attribute__((__unused__)))
274
337
{
275
337
  struct ext2_super_block *es;
276
337
  uint32_t fc, frc, fi;
277
278
337
  es = ext_get_super(pr, &fc, &fi, &frc);
279
337
  if (!es)
280
270
    return errno ? -errno : 1;
281
282
  /* Distinguish between ext3 and ext2 */
283
67
  if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
284
37
    return 1;
285
286
  /* Any features which ext2 doesn't understand */
287
30
  if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
288
18
      (fi  & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
289
21
    return 1;
290
291
9
  ext_get_info(pr, 2, es);
292
9
  return 0;
293
30
}
294
295
static int probe_ext3(blkid_probe pr,
296
    const struct blkid_idmag *mag __attribute__((__unused__)))
297
337
{
298
337
  struct ext2_super_block *es;
299
337
  uint32_t fc, frc, fi;
300
301
337
  es = ext_get_super(pr, &fc, &fi, &frc);
302
337
  if (!es)
303
270
    return errno ? -errno : 1;
304
305
  /* ext3 requires journal */
306
67
  if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
307
30
    return 1;
308
309
  /* Any features which ext3 doesn't understand */
310
37
  if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
311
13
      (fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
312
34
    return 1;
313
314
3
  ext_get_info(pr, 3, es);
315
3
  return 0;
316
37
}
317
318
319
static int probe_ext4dev(blkid_probe pr,
320
    const struct blkid_idmag *mag __attribute__((__unused__)))
321
337
{
322
337
  struct ext2_super_block *es;
323
337
  uint32_t fc, frc, fi;
324
325
337
  es = ext_get_super(pr, &fc, &fi, &frc);
326
337
  if (!es)
327
270
    return errno ? -errno : 1;
328
329
  /* Distinguish from jbd */
330
67
  if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
331
18
    return 1;
332
333
49
  if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS))
334
27
    return 1;
335
336
22
  ext_get_info(pr, 4, es);
337
22
  return 0;
338
49
}
339
340
static int probe_ext4(blkid_probe pr,
341
    const struct blkid_idmag *mag __attribute__((__unused__)))
342
337
{
343
337
  struct ext2_super_block *es;
344
337
  uint32_t fc, frc, fi;
345
346
337
  es = ext_get_super(pr, &fc, &fi, &frc);
347
337
  if (!es)
348
270
    return errno ? -errno : 1;
349
350
  /* Distinguish from jbd */
351
67
  if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
352
18
    return 1;
353
354
  /* Ext4 has at least one feature which ext3 doesn't understand */
355
49
  if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
356
22
      !(fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
357
16
    return 1;
358
359
  /*
360
   * If the filesystem is a OK for use by in-development
361
   * filesystem code, and ext4dev is supported or ext4 is not
362
   * supported, then don't call ourselves ext4, so we can redo
363
   * the detection and mark the filesystem as ext4dev.
364
   *
365
   * If the filesystem is marked as in use by production
366
   * filesystem, then it can only be used by ext4 and NOT by
367
   * ext4dev.
368
   */
369
33
  if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
370
13
    return 1;
371
372
20
  ext_get_info(pr, 4, es);
373
20
  return 0;
374
33
}
375
376
#define BLKID_EXT_MAGICS \
377
  { \
378
    {  \
379
      .magic = EXT_SB_MAGIC, \
380
      .len = sizeof(EXT_SB_MAGIC) - 1, \
381
      .kboff = EXT_SB_KBOFF, \
382
      .sboff = EXT_MAG_OFF \
383
    }, \
384
    { NULL } \
385
  }
386
387
const struct blkid_idinfo jbd_idinfo =
388
{
389
  .name   = "jbd",
390
  .usage    = BLKID_USAGE_OTHER,
391
  .probefunc  = probe_jbd,
392
  .magics   = BLKID_EXT_MAGICS
393
};
394
395
const struct blkid_idinfo ext2_idinfo =
396
{
397
  .name   = "ext2",
398
  .usage    = BLKID_USAGE_FILESYSTEM,
399
  .probefunc  = probe_ext2,
400
  .magics   = BLKID_EXT_MAGICS
401
};
402
403
const struct blkid_idinfo ext3_idinfo =
404
{
405
  .name   = "ext3",
406
  .usage    = BLKID_USAGE_FILESYSTEM,
407
  .probefunc  = probe_ext3,
408
  .magics   = BLKID_EXT_MAGICS
409
};
410
411
const struct blkid_idinfo ext4_idinfo =
412
{
413
  .name   = "ext4",
414
  .usage    = BLKID_USAGE_FILESYSTEM,
415
  .probefunc  = probe_ext4,
416
  .magics   = BLKID_EXT_MAGICS
417
};
418
419
const struct blkid_idinfo ext4dev_idinfo =
420
{
421
  .name   = "ext4dev",
422
  .usage    = BLKID_USAGE_FILESYSTEM,
423
  .probefunc  = probe_ext4dev,
424
  .magics   = BLKID_EXT_MAGICS
425
};
426