diff options
Diffstat (limited to 'libblkid/befs.c')
-rw-r--r-- | libblkid/befs.c | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/libblkid/befs.c b/libblkid/befs.c deleted file mode 100644 index 847860ad5..000000000 --- a/libblkid/befs.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (C) 2010 Jeroen Oortwijn <oortwijn@gmail.com> - * - * Partly based on the Haiku BFS driver by - * Axel Dörfler <axeld@pinc-software.de> - * - * Also inspired by the Linux BeFS driver by - * Will Dyson <will_dyson@pobox.com>, et al. - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <inttypes.h> -#include <byteswap.h> -#include "bitops.h" -#include "superblocks.h" - -#define B_OS_NAME_LENGTH 0x20 -#define SUPER_BLOCK_MAGIC1 0x42465331 /* BFS1 */ -#define SUPER_BLOCK_MAGIC2 0xdd121031 -#define SUPER_BLOCK_MAGIC3 0x15b6830e -#define SUPER_BLOCK_FS_ENDIAN 0x42494745 /* BIGE */ -#define INODE_MAGIC1 0x3bbe0ad9 -#define BPLUSTREE_MAGIC 0x69f6c2e8 -#define BPLUSTREE_NULL -1LL -#define NUM_DIRECT_BLOCKS 12 -#define B_UINT64_TYPE 0x554c4c47 /* ULLG */ -#define KEY_NAME "be:volume_id" -#define KEY_SIZE 8 -#define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \ - : be16_to_cpu(value)) -#define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \ - : be32_to_cpu(value)) -#define FS64_TO_CPU(value, fs_is_le) (fs_is_le ? le64_to_cpu(value) \ - : be64_to_cpu(value)) - -typedef struct block_run { - int32_t allocation_group; - uint16_t start; - uint16_t len; -} __attribute__((packed)) block_run, inode_addr; - -struct befs_super_block { - char name[B_OS_NAME_LENGTH]; - int32_t magic1; - int32_t fs_byte_order; - uint32_t block_size; - uint32_t block_shift; - int64_t num_blocks; - int64_t used_blocks; - int32_t inode_size; - int32_t magic2; - int32_t blocks_per_ag; - int32_t ag_shift; - int32_t num_ags; - int32_t flags; - block_run log_blocks; - int64_t log_start; - int64_t log_end; - int32_t magic3; - inode_addr root_dir; - inode_addr indices; - int32_t pad[8]; -} __attribute__((packed)); - -typedef struct data_stream { - block_run direct[NUM_DIRECT_BLOCKS]; - int64_t max_direct_range; - block_run indirect; - int64_t max_indirect_range; - block_run double_indirect; - int64_t max_double_indirect_range; - int64_t size; -} __attribute__((packed)) data_stream; - -struct befs_inode { - int32_t magic1; - inode_addr inode_num; - int32_t uid; - int32_t gid; - int32_t mode; - int32_t flags; - int64_t create_time; - int64_t last_modified_time; - inode_addr parent; - inode_addr attributes; - uint32_t type; - int32_t inode_size; - uint32_t etc; - data_stream data; - int32_t pad[4]; - int32_t small_data[0]; -} __attribute__((packed)); - -struct small_data { - uint32_t type; - uint16_t name_size; - uint16_t data_size; - char name[0]; -} __attribute__((packed)); - -struct bplustree_header { - uint32_t magic; - uint32_t node_size; - uint32_t max_number_of_levels; - uint32_t data_type; - int64_t root_node_pointer; - int64_t free_node_pointer; - int64_t maximum_size; -} __attribute__((packed)); - -struct bplustree_node { - int64_t left_link; - int64_t right_link; - int64_t overflow_link; - uint16_t all_key_count; - uint16_t all_key_length; - char name[0]; -} __attribute__((packed)); - -static unsigned char *get_block_run(blkid_probe pr, const struct befs_super_block *bs, - const struct block_run *br, int fs_le) -{ - return blkid_probe_get_buffer(pr, - ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le) - << FS32_TO_CPU(bs->ag_shift, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)), - (blkid_loff_t) FS16_TO_CPU(br->len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)); -} - -static unsigned char *get_custom_block_run(blkid_probe pr, - const struct befs_super_block *bs, - const struct block_run *br, - int64_t offset, uint32_t length, int fs_le) -{ - if (offset + length > (int64_t) FS16_TO_CPU(br->len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - return NULL; - - return blkid_probe_get_buffer(pr, - ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le) - << FS32_TO_CPU(bs->ag_shift, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - + offset, - length); -} - -static unsigned char *get_tree_node(blkid_probe pr, const struct befs_super_block *bs, - const struct data_stream *ds, - int64_t start, uint32_t length, int fs_le) -{ - if (start < (int64_t) FS64_TO_CPU(ds->max_direct_range, fs_le)) { - int64_t br_len; - size_t i; - - for (i = 0; i < NUM_DIRECT_BLOCKS; i++) { - br_len = (int64_t) FS16_TO_CPU(ds->direct[i].len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le); - if (start < br_len) - return get_custom_block_run(pr, bs, - &ds->direct[i], - start, length, fs_le); - else - start -= br_len; - } - } else if (start < (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le)) { - struct block_run *br; - int64_t max_br, br_len, i; - - start -= FS64_TO_CPU(ds->max_direct_range, fs_le); - max_br = ((int64_t) FS16_TO_CPU(ds->indirect.len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - / sizeof(struct block_run); - - br = (struct block_run *) get_block_run(pr, bs, &ds->indirect, - fs_le); - if (!br) - return NULL; - - for (i = 0; i < max_br; i++) { - br_len = (int64_t) FS16_TO_CPU(br[i].len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le); - if (start < br_len) - return get_custom_block_run(pr, bs, &br[i], - start, length, fs_le); - else - start -= br_len; - } - } else if (start < (int64_t) FS64_TO_CPU(ds->max_double_indirect_range, fs_le)) { - struct block_run *br; - int64_t di_br_size, br_per_di_br, di_index, i_index; - - start -= (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le); - - di_br_size = (int64_t) FS16_TO_CPU(ds->double_indirect.len, - fs_le) << FS32_TO_CPU(bs->block_shift, fs_le); - if (di_br_size == 0) - return NULL; - - br_per_di_br = di_br_size / sizeof(struct block_run); - if (br_per_di_br == 0) - return NULL; - - di_index = start / (br_per_di_br * di_br_size); - i_index = (start % (br_per_di_br * di_br_size)) / di_br_size; - start = (start % (br_per_di_br * di_br_size)) % di_br_size; - - br = (struct block_run *) get_block_run(pr, bs, - &ds->double_indirect, fs_le); - if (!br) - return NULL; - - br = (struct block_run *) get_block_run(pr, bs, &br[di_index], - fs_le); - if (!br) - return NULL; - - return get_custom_block_run(pr, bs, &br[i_index], start, length, - fs_le); - } - return NULL; -} - -static int32_t compare_keys(const char keys1[], uint16_t keylengths1[], int32_t index, - const char *key2, uint16_t keylength2, int fs_le) -{ - const char *key1; - uint16_t keylength1; - int32_t result; - - key1 = &keys1[index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1], - fs_le)]; - keylength1 = FS16_TO_CPU(keylengths1[index], fs_le) - - (index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1], - fs_le)); - - result = strncmp(key1, key2, min(keylength1, keylength2)); - - if (result == 0) - return keylength1 - keylength2; - - return result; -} - -static int64_t get_key_value(blkid_probe pr, const struct befs_super_block *bs, - const struct befs_inode *bi, const char *key, int fs_le) -{ - struct bplustree_header *bh; - struct bplustree_node *bn; - uint16_t *keylengths; - int64_t *values; - int64_t node_pointer; - int32_t first, last, mid, cmp; - - bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0, - sizeof(struct bplustree_header), fs_le); - if (!bh) - return -1; - - if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC) - return -1; - - node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le); - - do { - bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data, - node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le); - if (!bn) - return -1; - - keylengths = (uint16_t *) ((uint8_t *) bn - + ((sizeof(struct bplustree_node) - + FS16_TO_CPU(bn->all_key_length, fs_le) - + sizeof(int64_t) - 1) - & ~(sizeof(int64_t) - 1))); - values = (int64_t *) ((uint8_t *) keylengths - + FS16_TO_CPU(bn->all_key_count, fs_le) - * sizeof(uint16_t)); - first = 0; - mid = 0; - last = FS16_TO_CPU(bn->all_key_count, fs_le) - 1; - - cmp = compare_keys(bn->name, keylengths, last, key, strlen(key), - fs_le); - if (cmp == 0) { - if ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) - == BPLUSTREE_NULL) - return FS64_TO_CPU(values[last], fs_le); - else - node_pointer = FS64_TO_CPU(values[last], fs_le); - } else if (cmp < 0) - node_pointer = FS64_TO_CPU(bn->overflow_link, fs_le); - else { - while (first <= last) { - mid = (first + last) / 2; - - cmp = compare_keys(bn->name, keylengths, mid, - key, strlen(key), fs_le); - if (cmp == 0) { - if ((int64_t) FS64_TO_CPU(bn->overflow_link, - fs_le) == BPLUSTREE_NULL) - return FS64_TO_CPU(values[mid], - fs_le); - else - break; - } else if (cmp < 0) - first = mid + 1; - else - last = mid - 1; - } - if (cmp < 0) - node_pointer = FS64_TO_CPU(values[mid + 1], - fs_le); - else - node_pointer = FS64_TO_CPU(values[mid], fs_le); - } - } while ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) - != BPLUSTREE_NULL); - return 0; -} - -static int get_uuid(blkid_probe pr, const struct befs_super_block *bs, - uint64_t * const uuid, int fs_le) -{ - struct befs_inode *bi; - struct small_data *sd; - - bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le); - if (!bi) - return -1; - - if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) - return -1; - - sd = (struct small_data *) bi->small_data; - - do { - if (FS32_TO_CPU(sd->type, fs_le) == B_UINT64_TYPE - && FS16_TO_CPU(sd->name_size, fs_le) == strlen(KEY_NAME) - && FS16_TO_CPU(sd->data_size, fs_le) == KEY_SIZE - && strcmp(sd->name, KEY_NAME) == 0) { - - memcpy(uuid, - sd->name + FS16_TO_CPU(sd->name_size, fs_le) + 3, - sizeof(uint64_t)); - - break; - } else if (FS32_TO_CPU(sd->type, fs_le) == 0 - && FS16_TO_CPU(sd->name_size, fs_le) == 0 - && FS16_TO_CPU(sd->data_size, fs_le) == 0) - break; - - sd = (struct small_data *) ((uint8_t *) sd - + sizeof(struct small_data) - + FS16_TO_CPU(sd->name_size, fs_le) + 3 - + FS16_TO_CPU(sd->data_size, fs_le) + 1); - - } while ((intptr_t) sd < (intptr_t) bi - + (int32_t) FS32_TO_CPU(bi->inode_size, fs_le) - - (int32_t) sizeof(struct small_data)); - if (*uuid == 0 - && (FS32_TO_CPU(bi->attributes.allocation_group, fs_le) != 0 - || FS16_TO_CPU(bi->attributes.start, fs_le) != 0 - || FS16_TO_CPU(bi->attributes.len, fs_le) != 0)) { - int64_t value; - - bi = (struct befs_inode *) get_block_run(pr, bs, - &bi->attributes, fs_le); - if (!bi) - return -1; - - if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) - return -1; - - value = get_key_value(pr, bs, bi, KEY_NAME, fs_le); - - if (value < 0) - return value; - else if (value > 0) { - bi = (struct befs_inode *) blkid_probe_get_buffer(pr, - value << FS32_TO_CPU(bs->block_shift, fs_le), - FS32_TO_CPU(bs->block_size, fs_le)); - if (!bi) - return -1; - - if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) - return -1; - - if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE - && FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE - && FS16_TO_CPU(bi->data.direct[0].len, fs_le) - == 1) { - uint64_t *attr_data; - - attr_data = (uint64_t *) get_block_run(pr, bs, - &bi->data.direct[0], fs_le); - if (!attr_data) - return -1; - - *uuid = *attr_data; - } - } - } - return 0; -} - -static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct befs_super_block *bs; - const char *version = NULL; - uint64_t volume_id = 0; - int fs_le, ret; - - bs = (struct befs_super_block *) blkid_probe_get_buffer(pr, - mag->sboff - B_OS_NAME_LENGTH, - sizeof(struct befs_super_block)); - if (!bs) - return -1; - - if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 - && le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 - && le32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 - && le32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { - fs_le = 1; - version = "little-endian"; - } else if (be32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 - && be32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 - && be32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 - && be32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { - fs_le = 0; - version = "big-endian"; - } else - return -1; - - ret = get_uuid(pr, bs, &volume_id, fs_le); - - if (ret < 0) - return ret; - - /* - * all checks pass, set LABEL, VERSION and UUID - */ - if (strlen(bs->name)) - blkid_probe_set_label(pr, (unsigned char *) bs->name, - sizeof(bs->name)); - if (version) - blkid_probe_set_version(pr, version); - - if (volume_id) - blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id, - sizeof(volume_id), "%016" PRIx64, - FS64_TO_CPU(volume_id, fs_le)); - return 0; -} - -const struct blkid_idinfo befs_idinfo = -{ - .name = "befs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_befs, - .minsz = 1024 * 1440, - .magics = { - { .magic = "BFS1", .len = 4, .sboff = B_OS_NAME_LENGTH }, - { .magic = "1SFB", .len = 4, .sboff = B_OS_NAME_LENGTH }, - { .magic = "BFS1", .len = 4, .sboff = 0x200 + - B_OS_NAME_LENGTH }, - { .magic = "1SFB", .len = 4, .sboff = 0x200 + - B_OS_NAME_LENGTH }, - { NULL } - } -}; |