/src/util-linux/libblkid/src/superblocks/minix.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 1999 by Andries Brouwer |
3 | | * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o |
4 | | * Copyright (C) 2001 by Andreas Dilger |
5 | | * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> |
6 | | * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com> |
7 | | * |
8 | | * This file may be redistributed under the terms of the |
9 | | * GNU Lesser General Public License. |
10 | | */ |
11 | | |
12 | | #include <string.h> |
13 | | #include "superblocks.h" |
14 | | #include "minix.h" |
15 | | |
16 | 4.06k | #define minix_swab16(doit, num) ((uint16_t) (doit ? swab16(num) : num)) |
17 | 353 | #define minix_swab32(doit, num) ((uint32_t) (doit ? swab32(num) : num)) |
18 | | |
19 | | static int get_minix_version(const unsigned char *data, int *other_endian) |
20 | 1.22k | { |
21 | 1.22k | const struct minix_super_block *sb = (const struct minix_super_block *) data; |
22 | 1.22k | const struct minix3_super_block *sb3 = (const struct minix3_super_block *) data; |
23 | 1.22k | int version = 0; |
24 | 1.22k | char *endian; |
25 | | |
26 | 1.22k | *other_endian = 0; |
27 | | |
28 | 1.22k | switch (sb->s_magic) { |
29 | 259 | case MINIX_SUPER_MAGIC: |
30 | 404 | case MINIX_SUPER_MAGIC2: |
31 | 404 | version = 1; |
32 | 404 | break; |
33 | 103 | case MINIX2_SUPER_MAGIC: |
34 | 170 | case MINIX2_SUPER_MAGIC2: |
35 | 170 | version = 2; |
36 | 170 | break; |
37 | 653 | default: |
38 | 653 | if (sb3->s_magic == MINIX3_SUPER_MAGIC) |
39 | 117 | version = 3; |
40 | 653 | break; |
41 | 1.22k | } |
42 | | |
43 | 1.22k | if (!version) { |
44 | 536 | *other_endian = 1; |
45 | | |
46 | 536 | switch (swab16(sb->s_magic)) { |
47 | 177 | case MINIX_SUPER_MAGIC: |
48 | 295 | case MINIX_SUPER_MAGIC2: |
49 | 295 | version = 1; |
50 | 295 | break; |
51 | 4 | case MINIX2_SUPER_MAGIC: |
52 | 150 | case MINIX2_SUPER_MAGIC2: |
53 | 150 | version = 2; |
54 | 150 | break; |
55 | 91 | default: |
56 | 91 | if (sb3->s_magic == MINIX3_SUPER_MAGIC) |
57 | 0 | version = 3; |
58 | 91 | break; |
59 | 536 | } |
60 | 536 | } |
61 | 1.22k | if (!version) |
62 | 91 | return -1; |
63 | | |
64 | | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
65 | | endian = *other_endian ? "LE" : "BE"; |
66 | | #else |
67 | 1.13k | endian = *other_endian ? "BE" : "LE"; |
68 | 1.13k | #endif |
69 | 1.13k | DBG(LOWPROBE, ul_debug("minix version %d detected [%s]", version, |
70 | 1.13k | endian)); |
71 | 1.13k | return version; |
72 | 1.22k | } |
73 | | |
74 | | static int probe_minix(blkid_probe pr, |
75 | | const struct blkid_idmag *mag __attribute__((__unused__))) |
76 | 1.22k | { |
77 | 1.22k | const unsigned char *ext; |
78 | 1.22k | const unsigned char *erofs; |
79 | 1.22k | const unsigned char *data; |
80 | 1.22k | int version = 0, swabme = 0; |
81 | 1.22k | unsigned long zones, ninodes, imaps, zmaps; |
82 | 1.22k | off_t firstz; |
83 | 1.22k | size_t zone_size; |
84 | 1.22k | unsigned block_size; |
85 | | |
86 | 1.22k | data = blkid_probe_get_buffer(pr, 1024, |
87 | 1.22k | max(sizeof(struct minix_super_block), |
88 | 1.22k | sizeof(struct minix3_super_block))); |
89 | 1.22k | if (!data) |
90 | 0 | return errno ? -errno : 1; |
91 | 1.22k | version = get_minix_version(data, &swabme); |
92 | 1.22k | switch (version) { |
93 | 699 | case 1: |
94 | 1.01k | case 2: { |
95 | 1.01k | const struct minix_super_block *sb = (const struct minix_super_block *) data; |
96 | | |
97 | 1.01k | uint16_t state = minix_swab16(swabme, sb->s_state); |
98 | 1.01k | if ((state & (MINIX_VALID_FS | MINIX_ERROR_FS)) != state) |
99 | 569 | return 1; |
100 | | |
101 | 450 | zones = version == 2 ? minix_swab32(swabme, sb->s_zones) : |
102 | 450 | minix_swab16(swabme, sb->s_nzones); |
103 | 450 | ninodes = minix_swab16(swabme, sb->s_ninodes); |
104 | 450 | imaps = minix_swab16(swabme, sb->s_imap_blocks); |
105 | 450 | zmaps = minix_swab16(swabme, sb->s_zmap_blocks); |
106 | 450 | firstz = minix_swab16(swabme, sb->s_firstdatazone); |
107 | 450 | zone_size = sb->s_log_zone_size; |
108 | 450 | block_size = 1024; |
109 | 450 | break; |
110 | 1.01k | } |
111 | 117 | case 3: { |
112 | 117 | const struct minix3_super_block *sb = (const struct minix3_super_block *) data; |
113 | | |
114 | 117 | zones = minix_swab32(swabme, sb->s_zones); |
115 | 117 | ninodes = minix_swab32(swabme, sb->s_ninodes); |
116 | 117 | imaps = minix_swab16(swabme, sb->s_imap_blocks); |
117 | 117 | zmaps = minix_swab16(swabme, sb->s_zmap_blocks); |
118 | 117 | firstz = minix_swab16(swabme, sb->s_firstdatazone); |
119 | 117 | zone_size = sb->s_log_zone_size; |
120 | 117 | block_size = minix_swab16(swabme, sb->s_blocksize); |
121 | | |
122 | 117 | break; |
123 | 1.01k | } |
124 | 91 | default: |
125 | 91 | return 1; |
126 | 1.22k | } |
127 | | |
128 | | /* sanity checks to be sure that the FS is really minix. |
129 | | * see disk-utils/fsck.minix.c read_superblock |
130 | | */ |
131 | 567 | if (zone_size != 0 || ninodes == 0 || ninodes == UINT32_MAX) |
132 | 214 | return 1; |
133 | 353 | if (imaps * MINIX_BLOCK_SIZE * 8 < ninodes + 1) |
134 | 214 | return 1; |
135 | 139 | if (firstz > (off_t) zones) |
136 | 28 | return 1; |
137 | 111 | if (zmaps * MINIX_BLOCK_SIZE * 8 < zones - firstz + 1) |
138 | 60 | return 1; |
139 | | |
140 | | /* unfortunately, some parts of ext3 is sometimes possible to |
141 | | * interpreted as minix superblock. So check for extN magic |
142 | | * string. (For extN magic string and offsets see ext.c.) |
143 | | */ |
144 | 51 | ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2); |
145 | 51 | if (!ext) |
146 | 0 | return errno ? -errno : 1; |
147 | | |
148 | 51 | if (memcmp(ext, "\123\357", 2) == 0) |
149 | 26 | return 1; |
150 | | |
151 | | /* erofs superblock starts at 0x400 too, and its inode count field |
152 | | * overlaps the minix magic offset, so an erofs image can be |
153 | | * misinterpreted as minix. (For erofs magic and offsets see erofs.c.) |
154 | | */ |
155 | 25 | erofs = blkid_probe_get_buffer(pr, 0x400, 4); |
156 | 25 | if (!erofs) |
157 | 0 | return errno ? -errno : 1; |
158 | | |
159 | 25 | if (memcmp(erofs, "\xe2\xe1\xf5\xe0", 4) == 0) |
160 | 7 | return 1; |
161 | | |
162 | 18 | blkid_probe_sprintf_version(pr, "%d", version); |
163 | 18 | blkid_probe_set_fsblocksize(pr, block_size); |
164 | 18 | blkid_probe_set_block_size(pr, block_size); |
165 | 18 | blkid_probe_set_fsendianness(pr, !swabme ? |
166 | 10 | BLKID_ENDIANNESS_NATIVE : BLKID_ENDIANNESS_OTHER); |
167 | 18 | return 0; |
168 | 25 | } |
169 | | |
170 | | const struct blkid_idinfo minix_idinfo = |
171 | | { |
172 | | .name = "minix", |
173 | | .usage = BLKID_USAGE_FILESYSTEM, |
174 | | .probefunc = probe_minix, |
175 | | .magics = |
176 | | { |
177 | | /* version 1 - LE */ |
178 | | { .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 }, |
179 | | { .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 }, |
180 | | |
181 | | /* version 1 - BE */ |
182 | | { .magic = "\023\177", .len = 2, .kboff = 1, .sboff = 0x10 }, |
183 | | { .magic = "\023\217", .len = 2, .kboff = 1, .sboff = 0x10 }, |
184 | | |
185 | | /* version 2 - LE */ |
186 | | { .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 }, |
187 | | { .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 }, |
188 | | |
189 | | /* version 2 - BE */ |
190 | | { .magic = "\044\150", .len = 2, .kboff = 1, .sboff = 0x10 }, |
191 | | { .magic = "\044\170", .len = 2, .kboff = 1, .sboff = 0x10 }, |
192 | | |
193 | | /* version 3 - LE */ |
194 | | { .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 }, |
195 | | |
196 | | /* version 3 - BE */ |
197 | | { .magic = "\115\132", .len = 2, .kboff = 1, .sboff = 0x18 }, |
198 | | |
199 | | { NULL } |
200 | | } |
201 | | }; |
202 | | |