Coverage Report

Created: 2025-10-12 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/superblocks/f2fs.c
Line
Count
Source
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
274
{
62
274
  uint32_t csum_off = le32_to_cpu(sb->checksum_offset);
63
274
  if (!csum_off)
64
66
    return 1;
65
208
  if (csum_off % sizeof(uint32_t) != 0)
66
70
    return 0;
67
138
  if (csum_off + sizeof(uint32_t) > 4096)
68
112
    return 0;
69
70
26
  const unsigned char *csum_data = blkid_probe_get_buffer(pr,
71
26
      sb_off + csum_off, sizeof(uint32_t));
72
26
  if (!csum_data)
73
0
    return 0;
74
75
26
  uint32_t expected = le32_to_cpu(*(uint32_t *) csum_data);
76
77
26
  const unsigned char *csummed = blkid_probe_get_buffer(pr, sb_off, csum_off);
78
26
  if (!csummed)
79
0
    return 0;
80
81
26
  uint32_t csum = ul_crc32(0xF2F52010, csummed, csum_off);
82
83
26
  return blkid_probe_verify_csum(pr, csum, expected);
84
26
}
85
86
static int probe_f2fs(blkid_probe pr, const struct blkid_idmag *mag)
87
275
{
88
275
  const struct f2fs_super_block *sb;
89
275
  uint16_t vermaj, vermin;
90
91
275
  sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block);
92
275
  if (!sb)
93
0
    return errno ? -errno : 1;
94
95
275
  vermaj = le16_to_cpu(sb->major_ver);
96
275
  vermin = le16_to_cpu(sb->minor_ver);
97
98
  /* For version 1.0 we cannot know the correct sb structure */
99
275
  if (vermaj == 1 && vermin == 0)
100
1
    return 0;
101
102
274
  if (!f2fs_validate_checksum(pr, mag->kboff << 10, sb))
103
207
    return 1;
104
105
67
  if (*((unsigned char *) sb->volume_name))
106
33
    blkid_probe_set_utf8label(pr, (unsigned char *) sb->volume_name,
107
33
            sizeof(sb->volume_name),
108
33
            UL_ENCODE_UTF16LE);
109
110
67
  blkid_probe_set_uuid(pr, sb->uuid);
111
67
  blkid_probe_sprintf_version(pr, "%u.%u", vermaj, vermin);
112
67
  if (le32_to_cpu(sb->log_blocksize) < 32){
113
11
    uint32_t blocksize = 1U << le32_to_cpu(sb->log_blocksize);
114
11
    blkid_probe_set_fsblocksize(pr, blocksize);
115
11
    blkid_probe_set_block_size(pr, blocksize);
116
    blkid_probe_set_fssize(pr, le64_to_cpu(sb->block_count) * blocksize);
117
11
  }
118
67
  return 0;
119
274
}
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
};