]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libblkid/src/superblocks/f2fs.c
4e0fdbfe30549d63b63b30570198f91ea53f0ec4
[thirdparty/util-linux.git] / 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 const 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 const 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 const 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 };