/src/util-linux/libblkid/src/superblocks/befs.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2010 Jeroen Oortwijn <oortwijn@gmail.com> |
3 | | * |
4 | | * Partly based on the Haiku BFS driver by |
5 | | * Axel Dörfler <axeld@pinc-software.de> |
6 | | * |
7 | | * Also inspired by the Linux BeFS driver by |
8 | | * Will Dyson <will_dyson@pobox.com>, et al. |
9 | | * |
10 | | * This file may be redistributed under the terms of the |
11 | | * GNU Lesser General Public License. |
12 | | */ |
13 | | #include <stdio.h> |
14 | | #include <stdlib.h> |
15 | | #include <unistd.h> |
16 | | #include <string.h> |
17 | | #include <inttypes.h> |
18 | | |
19 | | #include "superblocks.h" |
20 | | |
21 | 2.34k | #define B_OS_NAME_LENGTH 0x20 |
22 | 6.59k | #define SUPER_BLOCK_MAGIC1 0x42465331 /* BFS1 */ |
23 | 5.64k | #define SUPER_BLOCK_MAGIC2 0xdd121031 |
24 | 4.82k | #define SUPER_BLOCK_MAGIC3 0x15b6830e |
25 | 1.47k | #define SUPER_BLOCK_FS_ENDIAN 0x42494745 /* BIGE */ |
26 | 2.43k | #define INODE_MAGIC1 0x3bbe0ad9 |
27 | 950 | #define BPLUSTREE_MAGIC 0x69f6c2e8 |
28 | 6.41k | #define BPLUSTREE_NULL -1LL |
29 | 295 | #define NUM_DIRECT_BLOCKS 12 |
30 | 8.27k | #define B_UINT64_TYPE 0x554c4c47 /* ULLG */ |
31 | 1.16k | #define KEY_NAME "be:volume_id" |
32 | 4.13k | #define KEY_SIZE 8 |
33 | | |
34 | 27.1M | #define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \ |
35 | 27.1M | : be16_to_cpu(value)) |
36 | 27.1M | #define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \ |
37 | 27.1M | : be32_to_cpu(value)) |
38 | 36.1k | #define FS64_TO_CPU(value, fs_is_le) (fs_is_le ? le64_to_cpu(value) \ |
39 | 36.1k | : be64_to_cpu(value)) |
40 | | |
41 | | typedef struct block_run { |
42 | | int32_t allocation_group; |
43 | | uint16_t start; |
44 | | uint16_t len; |
45 | | } __attribute__((packed)) block_run, inode_addr; |
46 | | |
47 | | struct befs_super_block { |
48 | | char name[B_OS_NAME_LENGTH]; |
49 | | int32_t magic1; |
50 | | int32_t fs_byte_order; |
51 | | uint32_t block_size; |
52 | | uint32_t block_shift; |
53 | | int64_t num_blocks; |
54 | | int64_t used_blocks; |
55 | | int32_t inode_size; |
56 | | int32_t magic2; |
57 | | int32_t blocks_per_ag; |
58 | | int32_t ag_shift; |
59 | | int32_t num_ags; |
60 | | int32_t flags; |
61 | | block_run log_blocks; |
62 | | int64_t log_start; |
63 | | int64_t log_end; |
64 | | int32_t magic3; |
65 | | inode_addr root_dir; |
66 | | inode_addr indices; |
67 | | int32_t pad[8]; |
68 | | } __attribute__((packed)); |
69 | | |
70 | | typedef struct data_stream { |
71 | | block_run direct[NUM_DIRECT_BLOCKS]; |
72 | | int64_t max_direct_range; |
73 | | block_run indirect; |
74 | | int64_t max_indirect_range; |
75 | | block_run double_indirect; |
76 | | int64_t max_double_indirect_range; |
77 | | int64_t size; |
78 | | } __attribute__((packed)) data_stream; |
79 | | |
80 | | struct befs_inode { |
81 | | int32_t magic1; |
82 | | inode_addr inode_num; |
83 | | int32_t uid; |
84 | | int32_t gid; |
85 | | int32_t mode; |
86 | | int32_t flags; |
87 | | int64_t create_time; |
88 | | int64_t last_modified_time; |
89 | | inode_addr parent; |
90 | | inode_addr attributes; |
91 | | uint32_t type; |
92 | | int32_t inode_size; |
93 | | uint32_t etc; |
94 | | data_stream data; |
95 | | int32_t pad[4]; |
96 | | int32_t small_data[0]; |
97 | | } __attribute__((packed)); |
98 | | |
99 | | struct small_data { |
100 | | uint32_t type; |
101 | | uint16_t name_size; |
102 | | uint16_t data_size; |
103 | | char name[0]; |
104 | | } __attribute__((packed)); |
105 | | |
106 | | struct bplustree_header { |
107 | | uint32_t magic; |
108 | | uint32_t node_size; |
109 | | uint32_t max_number_of_levels; |
110 | | uint32_t data_type; |
111 | | int64_t root_node_pointer; |
112 | | int64_t free_node_pointer; |
113 | | int64_t maximum_size; |
114 | | } __attribute__((packed)); |
115 | | |
116 | | struct bplustree_node { |
117 | | int64_t left_link; |
118 | | int64_t right_link; |
119 | | int64_t overflow_link; |
120 | | uint16_t all_key_count; |
121 | | uint16_t all_key_length; |
122 | | char name[0]; |
123 | | } __attribute__((packed)); |
124 | | |
125 | | static const unsigned char *get_block_run(blkid_probe pr, const struct befs_super_block *bs, |
126 | | const struct block_run *br, int fs_le) |
127 | 9.94k | { |
128 | 9.94k | return blkid_probe_get_buffer(pr, |
129 | 9.94k | ((uint64_t) FS32_TO_CPU(br->allocation_group, fs_le) |
130 | 9.94k | << FS32_TO_CPU(bs->ag_shift, fs_le) |
131 | 9.94k | << FS32_TO_CPU(bs->block_shift, fs_le)) |
132 | 9.94k | + ((uint64_t) FS16_TO_CPU(br->start, fs_le) |
133 | 9.94k | << FS32_TO_CPU(bs->block_shift, fs_le)), |
134 | 9.94k | (uint64_t) FS16_TO_CPU(br->len, fs_le) |
135 | 9.94k | << FS32_TO_CPU(bs->block_shift, fs_le)); |
136 | 9.94k | } |
137 | | |
138 | | static const unsigned char *get_custom_block_run(blkid_probe pr, |
139 | | const struct befs_super_block *bs, |
140 | | const struct block_run *br, |
141 | | int64_t offset, uint32_t length, int fs_le) |
142 | 7.22k | { |
143 | 7.22k | if (offset + length > (int64_t) FS16_TO_CPU(br->len, fs_le) |
144 | 7.22k | << FS32_TO_CPU(bs->block_shift, fs_le)) |
145 | 109 | return NULL; |
146 | | |
147 | 7.11k | return blkid_probe_get_buffer(pr, |
148 | 7.11k | ((uint64_t) FS32_TO_CPU(br->allocation_group, fs_le) |
149 | 7.11k | << FS32_TO_CPU(bs->ag_shift, fs_le) |
150 | 7.11k | << FS32_TO_CPU(bs->block_shift, fs_le)) |
151 | 7.11k | + ((uint64_t) FS16_TO_CPU(br->start, fs_le) |
152 | 7.11k | << FS32_TO_CPU(bs->block_shift, fs_le)) |
153 | 7.11k | + offset, |
154 | 7.11k | length); |
155 | 7.22k | } |
156 | | |
157 | | static const unsigned char *get_tree_node(blkid_probe pr, const struct befs_super_block *bs, |
158 | | const struct data_stream *ds, |
159 | | int64_t start, uint32_t length, int fs_le) |
160 | 7.70k | { |
161 | 7.70k | if (start < (int64_t) FS64_TO_CPU(ds->max_direct_range, fs_le)) { |
162 | 207 | int64_t br_len; |
163 | 207 | size_t i; |
164 | | |
165 | 295 | for (i = 0; i < NUM_DIRECT_BLOCKS; i++) { |
166 | 292 | br_len = (int64_t) FS16_TO_CPU(ds->direct[i].len, fs_le) |
167 | 292 | << FS32_TO_CPU(bs->block_shift, fs_le); |
168 | 292 | if (start < br_len) |
169 | 204 | return get_custom_block_run(pr, bs, |
170 | 204 | &ds->direct[i], |
171 | 204 | start, length, fs_le); |
172 | 88 | start -= br_len; |
173 | 88 | if (start < 0) |
174 | 0 | return NULL; /* Corrupt? */ |
175 | 88 | } |
176 | 7.49k | } else if (start < (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le)) { |
177 | 6.95k | struct block_run *br; |
178 | 6.95k | int64_t max_br, br_len, i; |
179 | | |
180 | 6.95k | start -= FS64_TO_CPU(ds->max_direct_range, fs_le); |
181 | 6.95k | if (start < 0) |
182 | 3 | return NULL; /* Corrupt? */ |
183 | | |
184 | 6.94k | max_br = ((int64_t) FS16_TO_CPU(ds->indirect.len, fs_le) |
185 | 6.94k | << FS32_TO_CPU(bs->block_shift, fs_le)) |
186 | 6.94k | / sizeof(struct block_run); |
187 | | |
188 | 6.94k | br = (struct block_run *) get_block_run(pr, bs, &ds->indirect, |
189 | 6.94k | fs_le); |
190 | 6.94k | if (!br) |
191 | 23 | return NULL; |
192 | | |
193 | 27.0M | for (i = 0; i < max_br; i++) { |
194 | 27.0M | br_len = (int64_t) FS16_TO_CPU(br[i].len, fs_le) |
195 | 27.0M | << FS32_TO_CPU(bs->block_shift, fs_le); |
196 | 27.0M | if (start < br_len) |
197 | 6.82k | return get_custom_block_run(pr, bs, &br[i], |
198 | 6.82k | start, length, fs_le); |
199 | 26.9M | start -= br_len; |
200 | 26.9M | } |
201 | 6.92k | } else if (start < (int64_t) FS64_TO_CPU(ds->max_double_indirect_range, fs_le)) { |
202 | 404 | struct block_run *br; |
203 | 404 | int64_t max_br, di_br_size, br_per_di_br, di_index, i_index; |
204 | | |
205 | 404 | start -= (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le); |
206 | 404 | if (start < 0) |
207 | 5 | return NULL; /* Corrupt? */ |
208 | | |
209 | 399 | di_br_size = (int64_t) FS16_TO_CPU(ds->double_indirect.len, |
210 | 399 | fs_le) << FS32_TO_CPU(bs->block_shift, fs_le); |
211 | 399 | if (di_br_size == 0) |
212 | 32 | return NULL; |
213 | | |
214 | 367 | br_per_di_br = di_br_size / sizeof(struct block_run); |
215 | 367 | if (br_per_di_br == 0) |
216 | 0 | return NULL; |
217 | | |
218 | 367 | di_index = start / (br_per_di_br * di_br_size); |
219 | 367 | i_index = (start % (br_per_di_br * di_br_size)) / di_br_size; |
220 | 367 | start = (start % (br_per_di_br * di_br_size)) % di_br_size; |
221 | | |
222 | 367 | if (di_index >= br_per_di_br) |
223 | 79 | return NULL; /* Corrupt? */ |
224 | | |
225 | 288 | br = (struct block_run *) get_block_run(pr, bs, |
226 | 288 | &ds->double_indirect, fs_le); |
227 | 288 | if (!br) |
228 | 17 | return NULL; |
229 | | |
230 | 271 | max_br = ((int64_t)FS16_TO_CPU(br[di_index].len, fs_le) |
231 | 271 | << FS32_TO_CPU(bs->block_shift, fs_le)) |
232 | 271 | / sizeof(struct block_run); |
233 | | |
234 | 271 | if (i_index >= max_br) |
235 | 37 | return NULL; /* Corrupt? */ |
236 | | |
237 | 234 | br = (struct block_run *) get_block_run(pr, bs, &br[di_index], |
238 | 234 | fs_le); |
239 | 234 | if (!br) |
240 | 39 | return NULL; |
241 | | |
242 | 195 | return get_custom_block_run(pr, bs, &br[i_index], start, length, |
243 | 195 | fs_le); |
244 | 234 | } |
245 | 245 | return NULL; |
246 | 7.70k | } |
247 | | |
248 | 13.1k | #define BAD_KEYS -2 |
249 | | |
250 | | static int32_t compare_keys(const char keys1[], uint16_t keylengths1[], |
251 | | int32_t index, const char *key2, |
252 | | uint16_t keylength2, uint16_t all_key_length, |
253 | | int fs_le) |
254 | 12.9k | { |
255 | 12.9k | const char *key1; |
256 | 12.9k | uint16_t keylength1, keystart1; |
257 | 12.9k | int32_t result; |
258 | | |
259 | 12.9k | keystart1 = index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1], fs_le); |
260 | 12.9k | keylength1 = FS16_TO_CPU(keylengths1[index], fs_le) - keystart1; |
261 | | |
262 | 12.9k | if (keystart1 + keylength1 > all_key_length) |
263 | 142 | return BAD_KEYS; /* Corrupt? */ |
264 | | |
265 | 12.8k | key1 = &keys1[keystart1]; |
266 | | |
267 | 12.8k | result = strncmp(key1, key2, min(keylength1, keylength2)); |
268 | | |
269 | 12.8k | if (result == 0) |
270 | 8.69k | return keylength1 - keylength2; |
271 | | |
272 | 4.13k | if (result < 0) /* Don't clash with BAD_KEYS */ |
273 | 1.93k | result = -1; |
274 | | |
275 | 4.13k | return result; |
276 | 12.8k | } |
277 | | |
278 | | static int64_t get_key_value(blkid_probe pr, const struct befs_super_block *bs, |
279 | | const struct befs_inode *bi, const char *key, int fs_le) |
280 | 1.14k | { |
281 | 1.14k | struct bplustree_header *bh; |
282 | 1.14k | struct bplustree_node *bn; |
283 | 1.14k | uint16_t *keylengths; |
284 | 1.14k | int64_t *values; |
285 | 1.14k | int64_t node_pointer; |
286 | 1.14k | uint32_t bn_size, all_key_count, all_key_length; |
287 | 1.14k | uint32_t keylengths_offset, values_offset; |
288 | 1.14k | int32_t first, last, mid, cmp; |
289 | 1.14k | int loop_detect = 0; |
290 | | |
291 | 1.14k | errno = 0; |
292 | 1.14k | bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0, |
293 | 1.14k | sizeof(struct bplustree_header), fs_le); |
294 | 1.14k | if (!bh) |
295 | 199 | return errno ? -errno : -ENOENT; |
296 | | |
297 | 950 | if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC) |
298 | 86 | return -ENOENT; |
299 | | |
300 | 864 | node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le); |
301 | 864 | bn_size = FS32_TO_CPU(bh->node_size, fs_le); |
302 | | |
303 | 864 | if (bn_size < sizeof(struct bplustree_node)) |
304 | 3 | return -ENOENT; /* Corrupt? */ |
305 | | |
306 | 6.55k | do { |
307 | 6.55k | errno = 0; |
308 | | |
309 | 6.55k | bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data, |
310 | 6.55k | node_pointer, bn_size, fs_le); |
311 | 6.55k | if (!bn) |
312 | 646 | return errno ? -errno : -ENOENT; |
313 | | |
314 | 5.91k | all_key_count = FS16_TO_CPU(bn->all_key_count, fs_le); |
315 | 5.91k | all_key_length = FS16_TO_CPU(bn->all_key_length, fs_le); |
316 | 5.91k | keylengths_offset = |
317 | 5.91k | (sizeof(struct bplustree_node) + all_key_length |
318 | 5.91k | + sizeof(int64_t) - 1) & ~(sizeof(int64_t) - 1); |
319 | 5.91k | values_offset = keylengths_offset + |
320 | 5.91k | all_key_count * sizeof(uint16_t); |
321 | | |
322 | 5.91k | if (values_offset + all_key_count * sizeof(uint64_t) > bn_size) |
323 | 24 | return -ENOENT; /* Corrupt? */ |
324 | | |
325 | 5.88k | keylengths = (uint16_t *) ((uint8_t *) bn + keylengths_offset); |
326 | 5.88k | values = (int64_t *) ((uint8_t *) bn + values_offset); |
327 | | |
328 | 5.88k | first = 0; |
329 | 5.88k | mid = 0; |
330 | 5.88k | last = all_key_count - 1; |
331 | | |
332 | 5.88k | cmp = compare_keys(bn->name, keylengths, last, key, |
333 | 5.88k | strlen(key), all_key_length, fs_le); |
334 | 5.88k | if (cmp == BAD_KEYS) |
335 | 84 | return -ENOENT; |
336 | | |
337 | 5.80k | if (cmp == 0) { |
338 | 411 | if ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) |
339 | 411 | == BPLUSTREE_NULL) |
340 | 1 | return FS64_TO_CPU(values[last], fs_le); |
341 | | |
342 | 410 | node_pointer = FS64_TO_CPU(values[last], fs_le); |
343 | 5.39k | } else if (cmp < 0) |
344 | 4.27k | node_pointer = FS64_TO_CPU(bn->overflow_link, fs_le); |
345 | 1.12k | else { |
346 | 7.83k | while (first <= last) { |
347 | 7.08k | mid = (first + last) / 2; |
348 | | |
349 | 7.08k | cmp = compare_keys(bn->name, keylengths, mid, |
350 | 7.08k | key, strlen(key), |
351 | 7.08k | all_key_length, fs_le); |
352 | 7.08k | if (cmp == BAD_KEYS) |
353 | 58 | return -ENOENT; |
354 | | |
355 | 7.02k | if (cmp == 0) { |
356 | 312 | if ((int64_t) FS64_TO_CPU(bn->overflow_link, |
357 | 312 | fs_le) == BPLUSTREE_NULL) |
358 | 1 | return FS64_TO_CPU(values[mid], |
359 | 312 | fs_le); |
360 | 311 | break; |
361 | 312 | } |
362 | | |
363 | 6.71k | if (cmp < 0) |
364 | 5.28k | first = mid + 1; |
365 | 1.42k | else |
366 | 1.42k | last = mid - 1; |
367 | 6.71k | } |
368 | 1.06k | if (cmp < 0) |
369 | 332 | node_pointer = FS64_TO_CPU(values[mid + 1], |
370 | 1.06k | fs_le); |
371 | 730 | else |
372 | 730 | node_pointer = FS64_TO_CPU(values[mid], fs_le); |
373 | 1.06k | } |
374 | 5.80k | } while (++loop_detect < 100 && |
375 | 5.69k | (int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) |
376 | 5.69k | != BPLUSTREE_NULL); |
377 | 47 | return 0; |
378 | 861 | } |
379 | | |
380 | | static int get_uuid(blkid_probe pr, const struct befs_super_block *bs, |
381 | | uint64_t * const uuid, int fs_le) |
382 | 1.26k | { |
383 | 1.26k | struct befs_inode *bi; |
384 | 1.26k | struct small_data *sd; |
385 | 1.26k | uint64_t bi_size, offset, sd_size, sd_total_size; |
386 | | |
387 | 1.26k | bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le); |
388 | 1.26k | if (!bi) |
389 | 9 | return errno ? -errno : BLKID_PROBE_NONE; |
390 | | |
391 | 1.25k | if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) |
392 | 49 | return BLKID_PROBE_NONE; |
393 | | |
394 | 1.20k | bi_size = (uint64_t)FS16_TO_CPU(bs->root_dir.len, fs_le) << |
395 | 1.20k | FS32_TO_CPU(bs->block_shift, fs_le); |
396 | 1.20k | sd_total_size = min(bi_size - sizeof(struct befs_inode), |
397 | 1.20k | (uint64_t)FS32_TO_CPU(bi->inode_size, fs_le)); |
398 | | |
399 | 1.20k | offset = 0; |
400 | | |
401 | 4.47k | while (offset + sizeof(struct small_data) <= sd_total_size) { |
402 | 4.45k | sd = (struct small_data *) ((uint8_t *)bi->small_data + offset); |
403 | 4.45k | sd_size = sizeof(struct small_data) |
404 | 4.45k | + FS16_TO_CPU(sd->name_size, fs_le) + 3 |
405 | 4.45k | + FS16_TO_CPU(sd->data_size, fs_le) + 1; |
406 | | |
407 | 4.45k | if (offset + sd_size > sd_total_size) |
408 | 315 | break; |
409 | | |
410 | 4.13k | if (FS32_TO_CPU(sd->type, fs_le) == B_UINT64_TYPE |
411 | 12 | && FS16_TO_CPU(sd->name_size, fs_le) == strlen(KEY_NAME) |
412 | 0 | && FS16_TO_CPU(sd->data_size, fs_le) == KEY_SIZE |
413 | 0 | && strcmp(sd->name, KEY_NAME) == 0) { |
414 | |
|
415 | 0 | memcpy(uuid, |
416 | 0 | sd->name + FS16_TO_CPU(sd->name_size, fs_le) + 3, |
417 | 0 | sizeof(uint64_t)); |
418 | |
|
419 | 0 | break; |
420 | 0 | } |
421 | | |
422 | 4.13k | if (FS32_TO_CPU(sd->type, fs_le) == 0 |
423 | 1.28k | && FS16_TO_CPU(sd->name_size, fs_le) == 0 |
424 | 1.08k | && FS16_TO_CPU(sd->data_size, fs_le) == 0) |
425 | 867 | break; |
426 | | |
427 | 3.26k | offset += sd_size; |
428 | 3.26k | } |
429 | | |
430 | 1.20k | if (*uuid == 0 |
431 | 1.20k | && (FS32_TO_CPU(bi->attributes.allocation_group, fs_le) != 0 |
432 | 42 | || FS16_TO_CPU(bi->attributes.start, fs_le) != 0 |
433 | 1.20k | || FS16_TO_CPU(bi->attributes.len, fs_le) != 0)) { |
434 | 1.20k | int64_t value; |
435 | | |
436 | 1.20k | bi = (struct befs_inode *) get_block_run(pr, bs, |
437 | 1.20k | &bi->attributes, fs_le); |
438 | 1.20k | if (!bi) |
439 | 33 | return errno ? -errno : BLKID_PROBE_NONE; |
440 | | |
441 | 1.17k | if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) |
442 | 26 | return BLKID_PROBE_NONE; |
443 | | |
444 | 1.14k | value = get_key_value(pr, bs, bi, KEY_NAME, fs_le); |
445 | 1.14k | if (value < 0) |
446 | 1.10k | return value == -ENOENT ? BLKID_PROBE_NONE : value; |
447 | | |
448 | 49 | if (value > 0) { |
449 | 0 | bi = (struct befs_inode *) blkid_probe_get_buffer(pr, |
450 | 0 | value << FS32_TO_CPU(bs->block_shift, fs_le), |
451 | 0 | FS32_TO_CPU(bs->block_size, fs_le)); |
452 | 0 | if (!bi) |
453 | 0 | return errno ? -errno : BLKID_PROBE_NONE; |
454 | | |
455 | 0 | if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) |
456 | 0 | return 1; |
457 | | |
458 | 0 | if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE |
459 | 0 | && FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE |
460 | 0 | && FS16_TO_CPU(bi->data.direct[0].len, fs_le) |
461 | 0 | == 1) { |
462 | 0 | uint64_t *attr_data; |
463 | |
|
464 | 0 | attr_data = (uint64_t *) get_block_run(pr, bs, |
465 | 0 | &bi->data.direct[0], fs_le); |
466 | 0 | if (!attr_data) |
467 | 0 | return errno ? -errno : BLKID_PROBE_NONE; |
468 | | |
469 | 0 | *uuid = *attr_data; |
470 | 0 | } |
471 | 0 | } |
472 | 49 | } |
473 | 50 | return 0; |
474 | 1.20k | } |
475 | | |
476 | | static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag) |
477 | 2.34k | { |
478 | 2.34k | struct befs_super_block *bs; |
479 | 2.34k | const char *version = NULL; |
480 | 2.34k | uint64_t volume_id = 0; |
481 | 2.34k | uint32_t block_size, block_shift; |
482 | 2.34k | int fs_le, ret; |
483 | | |
484 | 2.34k | bs = (struct befs_super_block *) blkid_probe_get_buffer(pr, |
485 | 2.34k | mag->sboff - B_OS_NAME_LENGTH, |
486 | 2.34k | sizeof(struct befs_super_block)); |
487 | 2.34k | if (!bs) |
488 | 0 | return errno ? -errno : BLKID_PROBE_NONE; |
489 | | |
490 | 2.34k | if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 |
491 | 1.82k | && le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 |
492 | 1.49k | && le32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 |
493 | 1.45k | && le32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { |
494 | 1.39k | fs_le = 1; |
495 | 1.39k | version = "little-endian"; |
496 | 1.39k | } else if (be32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 |
497 | 518 | && be32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 |
498 | 37 | && be32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 |
499 | 25 | && be32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { |
500 | 18 | fs_le = 0; |
501 | 18 | version = "big-endian"; |
502 | 18 | } else |
503 | 935 | return BLKID_PROBE_NONE; |
504 | | |
505 | 1.41k | block_size = FS32_TO_CPU(bs->block_size, fs_le); |
506 | 1.41k | block_shift = FS32_TO_CPU(bs->block_shift, fs_le); |
507 | | |
508 | 1.41k | if (block_shift < 10 || block_shift > 13 || |
509 | 1.33k | block_size != 1U << block_shift) |
510 | 93 | return BLKID_PROBE_NONE; |
511 | | |
512 | 1.31k | if (FS32_TO_CPU(bs->ag_shift, fs_le) > 64) |
513 | 50 | return BLKID_PROBE_NONE; |
514 | | |
515 | 1.26k | ret = get_uuid(pr, bs, &volume_id, fs_le); |
516 | | |
517 | 1.26k | if (ret != 0) |
518 | 1.21k | return ret; |
519 | | |
520 | | /* |
521 | | * all checks pass, set LABEL, VERSION and UUID |
522 | | */ |
523 | 50 | if (*bs->name != '\0') |
524 | 50 | blkid_probe_set_label(pr, (unsigned char *) bs->name, |
525 | 50 | sizeof(bs->name)); |
526 | 50 | if (version) |
527 | 50 | blkid_probe_set_version(pr, version); |
528 | | |
529 | 50 | if (volume_id) |
530 | 0 | blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id, |
531 | 0 | sizeof(volume_id), "%016" PRIx64, |
532 | 0 | FS64_TO_CPU(volume_id, fs_le)); |
533 | | |
534 | 50 | blkid_probe_set_fsblocksize(pr, block_size); |
535 | 50 | blkid_probe_set_block_size(pr, block_size); |
536 | 50 | blkid_probe_set_fsendianness(pr, |
537 | 50 | fs_le ? BLKID_ENDIANNESS_LITTLE : BLKID_ENDIANNESS_BIG); |
538 | | |
539 | 50 | return BLKID_PROBE_OK; |
540 | 1.26k | } |
541 | | |
542 | | const struct blkid_idinfo befs_idinfo = |
543 | | { |
544 | | .name = "befs", |
545 | | .usage = BLKID_USAGE_FILESYSTEM, |
546 | | .probefunc = probe_befs, |
547 | | .minsz = 1024 * 1440, |
548 | | .magics = { |
549 | | { .magic = "BFS1", .len = 4, .sboff = B_OS_NAME_LENGTH }, |
550 | | { .magic = "1SFB", .len = 4, .sboff = B_OS_NAME_LENGTH }, |
551 | | { .magic = "BFS1", .len = 4, .sboff = 0x200 + |
552 | | B_OS_NAME_LENGTH }, |
553 | | { .magic = "1SFB", .len = 4, .sboff = 0x200 + |
554 | | B_OS_NAME_LENGTH }, |
555 | | { NULL } |
556 | | } |
557 | | }; |