summaryrefslogtreecommitdiff
path: root/libblkid/src/superblocks
diff options
context:
space:
mode:
Diffstat (limited to 'libblkid/src/superblocks')
-rw-r--r--libblkid/src/superblocks/adaptec_raid.c114
-rw-r--r--libblkid/src/superblocks/befs.c478
-rw-r--r--libblkid/src/superblocks/bfs.c23
-rw-r--r--libblkid/src/superblocks/btrfs.c93
-rw-r--r--libblkid/src/superblocks/cramfs.c62
-rw-r--r--libblkid/src/superblocks/ddf_raid.c139
-rw-r--r--libblkid/src/superblocks/drbd.c117
-rw-r--r--libblkid/src/superblocks/drbdproxy_datalog.c55
-rw-r--r--libblkid/src/superblocks/exfat.c146
-rw-r--r--libblkid/src/superblocks/ext.c540
-rw-r--r--libblkid/src/superblocks/gfs.c131
-rw-r--r--libblkid/src/superblocks/hfs.c321
-rw-r--r--libblkid/src/superblocks/highpoint_raid.c87
-rw-r--r--libblkid/src/superblocks/hpfs.c122
-rw-r--r--libblkid/src/superblocks/iso9660.c215
-rw-r--r--libblkid/src/superblocks/isw_raid.c65
-rw-r--r--libblkid/src/superblocks/jfs.c71
-rw-r--r--libblkid/src/superblocks/jmicron_raid.c64
-rw-r--r--libblkid/src/superblocks/linux_raid.c258
-rw-r--r--libblkid/src/superblocks/lsi_raid.c60
-rw-r--r--libblkid/src/superblocks/luks.c66
-rw-r--r--libblkid/src/superblocks/lvm.c228
-rw-r--r--libblkid/src/superblocks/minix.c94
-rw-r--r--libblkid/src/superblocks/netware.c97
-rw-r--r--libblkid/src/superblocks/nilfs.c120
-rw-r--r--libblkid/src/superblocks/ntfs.c224
-rw-r--r--libblkid/src/superblocks/nvidia_raid.c64
-rw-r--r--libblkid/src/superblocks/ocfs.c213
-rw-r--r--libblkid/src/superblocks/promise_raid.c71
-rw-r--r--libblkid/src/superblocks/reiserfs.c128
-rw-r--r--libblkid/src/superblocks/romfs.c51
-rw-r--r--libblkid/src/superblocks/silicon_raid.c85
-rw-r--r--libblkid/src/superblocks/squashfs.c68
-rw-r--r--libblkid/src/superblocks/superblocks.c768
-rw-r--r--libblkid/src/superblocks/superblocks.h92
-rw-r--r--libblkid/src/superblocks/swap.c171
-rw-r--r--libblkid/src/superblocks/sysv.c154
-rw-r--r--libblkid/src/superblocks/ubifs.c120
-rw-r--r--libblkid/src/superblocks/udf.c169
-rw-r--r--libblkid/src/superblocks/ufs.c258
-rw-r--r--libblkid/src/superblocks/vfat.c427
-rw-r--r--libblkid/src/superblocks/via_raid.c89
-rw-r--r--libblkid/src/superblocks/vmfs.c101
-rw-r--r--libblkid/src/superblocks/vxfs.c41
-rw-r--r--libblkid/src/superblocks/xfs.c63
-rw-r--r--libblkid/src/superblocks/zfs.c226
46 files changed, 7349 insertions, 0 deletions
diff --git a/libblkid/src/superblocks/adaptec_raid.c b/libblkid/src/superblocks/adaptec_raid.c
new file mode 100644
index 0000000..02e900d
--- /dev/null
+++ b/libblkid/src/superblocks/adaptec_raid.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct adaptec_metadata {
+
+ uint32_t b0idcode;
+ uint8_t lunsave[8];
+ uint16_t sdtype;
+ uint16_t ssavecyl;
+ uint8_t ssavehed;
+ uint8_t ssavesec;
+ uint8_t sb0flags;
+ uint8_t jbodEnable;
+ uint8_t lundsave;
+ uint8_t svpdirty;
+ uint16_t biosInfo;
+ uint16_t svwbskip;
+ uint16_t svwbcln;
+ uint16_t svwbmax;
+ uint16_t res3;
+ uint16_t svwbmin;
+ uint16_t res4;
+ uint16_t svrcacth;
+ uint16_t svwcacth;
+ uint16_t svwbdly;
+ uint8_t svsdtime;
+ uint8_t res5;
+ uint16_t firmval;
+ uint16_t firmbln;
+ uint32_t firmblk;
+ uint32_t fstrsvrb;
+ uint16_t svBlockStorageTid;
+ uint16_t svtid;
+ uint8_t svseccfl;
+ uint8_t res6;
+ uint8_t svhbanum;
+ uint8_t resver;
+ uint32_t drivemagic;
+ uint8_t reserved[20];
+ uint8_t testnum;
+ uint8_t testflags;
+ uint16_t maxErrorCount;
+ uint32_t count;
+ uint32_t startTime;
+ uint32_t interval;
+ uint8_t tstxt0;
+ uint8_t tstxt1;
+ uint8_t serNum[32];
+ uint8_t res8[102];
+ uint32_t fwTestMagic;
+ uint32_t fwTestSeqNum;
+ uint8_t fwTestRes[8];
+ uint32_t smagic;
+ uint32_t raidtbl;
+ uint16_t raidline;
+ uint8_t res9[0xF6];
+} __attribute__((packed));
+
+#define AD_SIGNATURE 0x4450544D /* "DPTM" */
+#define AD_MAGIC 0x37FC4D1E
+
+static int probe_adraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t off;
+ struct adaptec_metadata *ad;
+
+ if (pr->size < 0x10000)
+ return -1;
+
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200)-1) * 0x200;
+ ad = (struct adaptec_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct adaptec_metadata));
+ if (!ad)
+ return -1;
+ if (ad->smagic != be32_to_cpu(AD_SIGNATURE))
+ return -1;
+ if (ad->b0idcode != be32_to_cpu(AD_MAGIC))
+ return -1;
+ if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(ad->b0idcode),
+ (unsigned char *) &ad->b0idcode))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo adraid_idinfo = {
+ .name = "adaptec_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_adraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/befs.c b/libblkid/src/superblocks/befs.c
new file mode 100644
index 0000000..a7f4317
--- /dev/null
+++ b/libblkid/src/superblocks/befs.c
@@ -0,0 +1,478 @@
+/*
+ * 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 "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) {
+ *uuid = *(uint64_t *) ((uint8_t *) sd->name
+ + FS16_TO_CPU(sd->name_size, fs_le)
+ + 3);
+ 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 }
+ }
+};
diff --git a/libblkid/src/superblocks/bfs.c b/libblkid/src/superblocks/bfs.c
new file mode 100644
index 0000000..8a34c58
--- /dev/null
+++ b/libblkid/src/superblocks/bfs.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include "superblocks.h"
+
+/*
+ * BFS actually has two different labels in the superblock, each
+ * of them only 6 bytes long. Until we find out what their use
+ * we just ignore them.
+ */
+const struct blkid_idinfo bfs_idinfo =
+{
+ .name = "bfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .magics = {
+ { .magic = "\xce\xfa\xad\x1b", .len = 4 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/btrfs.c b/libblkid/src/superblocks/btrfs.c
new file mode 100644
index 0000000..039be42
--- /dev/null
+++ b/libblkid/src/superblocks/btrfs.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct btrfs_super_block {
+ uint8_t csum[32];
+ uint8_t fsid[16];
+ uint64_t bytenr;
+ uint64_t flags;
+ uint8_t magic[8];
+ uint64_t generation;
+ uint64_t root;
+ uint64_t chunk_root;
+ uint64_t log_root;
+ uint64_t log_root_transid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint64_t root_dir_objectid;
+ uint64_t num_devices;
+ uint32_t sectorsize;
+ uint32_t nodesize;
+ uint32_t leafsize;
+ uint32_t stripesize;
+ uint32_t sys_chunk_array_size;
+ uint64_t chunk_root_generation;
+ uint64_t compat_flags;
+ uint64_t compat_ro_flags;
+ uint64_t incompat_flags;
+ uint16_t csum_type;
+ uint8_t root_level;
+ uint8_t chunk_root_level;
+ uint8_t log_root_level;
+ struct btrfs_dev_item {
+ uint64_t devid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint32_t io_align;
+ uint32_t io_width;
+ uint32_t sector_size;
+ uint64_t type;
+ uint64_t generation;
+ uint64_t start_offset;
+ uint32_t dev_group;
+ uint8_t seek_speed;
+ uint8_t bandwidth;
+ uint8_t uuid[16];
+ uint8_t fsid[16];
+ } __attribute__ ((__packed__)) dev_item;
+ uint8_t label[256];
+} __attribute__ ((__packed__));
+
+static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct btrfs_super_block *bfs;
+
+ bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block);
+ if (!bfs)
+ return -1;
+
+ if (*bfs->label)
+ blkid_probe_set_label(pr,
+ (unsigned char *) bfs->label,
+ sizeof(bfs->label));
+
+ blkid_probe_set_uuid(pr, bfs->fsid);
+ blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "UUID_SUB");
+
+ return 0;
+}
+
+const struct blkid_idinfo btrfs_idinfo =
+{
+ .name = "btrfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_btrfs,
+ .minsz = 1024 * 1024,
+ .magics =
+ {
+ { .magic = "_BHRfS_M", .len = 8, .kboff = 64, .sboff = 0x40 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/cramfs.c b/libblkid/src/superblocks/cramfs.c
new file mode 100644
index 0000000..b58ed08
--- /dev/null
+++ b/libblkid/src/superblocks/cramfs.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct cramfs_super
+{
+ uint8_t magic[4];
+ uint32_t size;
+ uint32_t flags;
+ uint32_t future;
+ uint8_t signature[16];
+ struct cramfs_info
+ {
+ uint32_t crc;
+ uint32_t edition;
+ uint32_t blocks;
+ uint32_t files;
+ } __attribute__((packed)) info;
+ uint8_t name[16];
+} __attribute__((packed));
+
+static int probe_cramfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct cramfs_super *cs;
+
+ cs = blkid_probe_get_sb(pr, mag, struct cramfs_super);
+ if (!cs)
+ return -1;
+
+ blkid_probe_set_label(pr, cs->name, sizeof(cs->name));
+ return 0;
+}
+
+const struct blkid_idinfo cramfs_idinfo =
+{
+ .name = "cramfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_cramfs,
+ .magics =
+ {
+ { "\x45\x3d\xcd\x28", 4, 0, 0 },
+ { "\x28\xcd\x3d\x45", 4, 0, 0 },
+ { NULL }
+ }
+};
+
+
diff --git a/libblkid/src/superblocks/ddf_raid.c b/libblkid/src/superblocks/ddf_raid.c
new file mode 100644
index 0000000..24df421
--- /dev/null
+++ b/libblkid/src/superblocks/ddf_raid.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+/* http://www.snia.org/standards/home */
+#define DDF_GUID_LENGTH 24
+#define DDF_REV_LENGTH 8
+#define DDF_MAGIC 0xDE11DE11
+
+
+struct ddf_header {
+ uint32_t signature;
+ uint32_t crc;
+ uint8_t guid[DDF_GUID_LENGTH];
+ char ddf_rev[8]; /* 01.02.00 */
+ uint32_t seq; /* starts at '1' */
+ uint32_t timestamp;
+ uint8_t openflag;
+ uint8_t foreignflag;
+ uint8_t enforcegroups;
+ uint8_t pad0; /* 0xff */
+ uint8_t pad1[12]; /* 12 * 0xff */
+ /* 64 bytes so far */
+ uint8_t header_ext[32]; /* reserved: fill with 0xff */
+ uint64_t primary_lba;
+ uint64_t secondary_lba;
+ uint8_t type;
+ uint8_t pad2[3]; /* 0xff */
+ uint32_t workspace_len; /* sectors for vendor space -
+ * at least 32768(sectors) */
+ uint64_t workspace_lba;
+ uint16_t max_pd_entries; /* one of 15, 63, 255, 1023, 4095 */
+ uint16_t max_vd_entries; /* 2^(4,6,8,10,12)-1 : i.e. as above */
+ uint16_t max_partitions; /* i.e. max num of configuration
+ record entries per disk */
+ uint16_t config_record_len; /* 1 +ROUNDUP(max_primary_element_entries
+ *12/512) */
+ uint16_t max_primary_element_entries; /* 16, 64, 256, 1024, or 4096 */
+ uint8_t pad3[54]; /* 0xff */
+ /* 192 bytes so far */
+ uint32_t controller_section_offset;
+ uint32_t controller_section_length;
+ uint32_t phys_section_offset;
+ uint32_t phys_section_length;
+ uint32_t virt_section_offset;
+ uint32_t virt_section_length;
+ uint32_t config_section_offset;
+ uint32_t config_section_length;
+ uint32_t data_section_offset;
+ uint32_t data_section_length;
+ uint32_t bbm_section_offset;
+ uint32_t bbm_section_length;
+ uint32_t diag_space_offset;
+ uint32_t diag_space_length;
+ uint32_t vendor_offset;
+ uint32_t vendor_length;
+ /* 256 bytes so far */
+ uint8_t pad4[256]; /* 0xff */
+} __attribute__((packed));
+
+static int probe_ddf(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ int hdrs[] = { 1, 257 };
+ size_t i;
+ struct ddf_header *ddf = NULL;
+ char version[DDF_REV_LENGTH + 1];
+ uint64_t off, lba;
+
+ if (pr->size < 0x30000)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE(hdrs); i++) {
+ off = ((pr->size / 0x200) - hdrs[i]) * 0x200;
+
+ ddf = (struct ddf_header *) blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct ddf_header));
+ if (!ddf)
+ return -1;
+
+ if (ddf->signature == cpu_to_be32(DDF_MAGIC) ||
+ ddf->signature == cpu_to_le32(DDF_MAGIC))
+ break;
+ ddf = NULL;
+ }
+
+ if (!ddf)
+ return -1;
+
+ lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ?
+ be64_to_cpu(ddf->primary_lba) :
+ le64_to_cpu(ddf->primary_lba);
+
+ if (lba > 0) {
+ /* check primary header */
+ unsigned char *buf;
+
+ buf = blkid_probe_get_buffer(pr,
+ lba << 9, sizeof(ddf->signature));
+ if (!buf || memcmp(buf, &ddf->signature, 4))
+ return -1;
+ }
+
+ blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid));
+
+ memcpy(version, ddf->ddf_rev, sizeof(ddf->ddf_rev));
+ *(version + sizeof(ddf->ddf_rev)) = '\0';
+
+ if (blkid_probe_set_version(pr, version) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off,
+ sizeof(ddf->signature),
+ (unsigned char *) &ddf->signature))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo ddfraid_idinfo = {
+ .name = "ddf_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_ddf,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/drbd.c b/libblkid/src/superblocks/drbd.c
new file mode 100644
index 0000000..43e544e
--- /dev/null
+++ b/libblkid/src/superblocks/drbd.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 by Bastian Friedrich <bastian.friedrich@collax.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * defines, structs taken from drbd source; file names represent drbd source
+ * files.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+/*
+ * drbd/linux/drbd.h
+ */
+#define DRBD_MAGIC 0x83740267
+
+/*
+ * user/drbdmeta.c
+ * We only support v08 for now
+ */
+#define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4)
+#define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5)
+
+/*
+ * drbd/linux/drbd.h
+ */
+enum drbd_uuid_index {
+ UI_CURRENT,
+ UI_BITMAP,
+ UI_HISTORY_START,
+ UI_HISTORY_END,
+ UI_SIZE, /* nl-packet: number of dirty bits */
+ UI_FLAGS, /* nl-packet: flags */
+ UI_EXTENDED_SIZE /* Everything. */
+};
+
+/*
+ * user/drbdmeta.c
+ * Minor modifications wrt. types
+ */
+struct md_on_disk_08 {
+ uint64_t la_sect; /* last agreed size. */
+ uint64_t uuid[UI_SIZE]; /* UUIDs */
+ uint64_t device_uuid;
+ uint64_t reserved_u64_1;
+ uint32_t flags;
+ uint32_t magic;
+ uint32_t md_size_sect;
+ int32_t al_offset; /* signed sector offset to this block */
+ uint32_t al_nr_extents; /* important for restoring the AL */
+ int32_t bm_offset; /* signed sector offset to the bitmap, from here */
+ uint32_t bm_bytes_per_bit;
+ uint32_t reserved_u32[4];
+
+ char reserved[8 * 512 - (8*(UI_SIZE+3)+4*11)];
+};
+
+
+static int probe_drbd(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct md_on_disk_08 *md;
+ off_t off;
+
+ off = pr->size - sizeof(*md);
+
+ /* Small devices cannot be drbd (?) */
+ if (pr->size < 0x10000)
+ return -1;
+
+ md = (struct md_on_disk_08 *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct md_on_disk_08));
+ if (!md)
+ return -1;
+
+ if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 &&
+ be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN)
+ return -1;
+
+ /*
+ * DRBD does not have "real" uuids; the following resembles DRBD's
+ * notion of uuids (64 bit, see struct above)
+ */
+ blkid_probe_sprintf_uuid(pr,
+ (unsigned char *) &md->device_uuid, sizeof(md->device_uuid),
+ "%" PRIx64, be64_to_cpu(md->device_uuid));
+
+ blkid_probe_set_version(pr, "v08");
+
+ if (blkid_probe_set_magic(pr,
+ off + offsetof(struct md_on_disk_08, magic),
+ sizeof(md->magic),
+ (unsigned char *) &md->magic))
+ return -1;
+
+ return 0;
+}
+
+const struct blkid_idinfo drbd_idinfo =
+{
+ .name = "drbd",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_drbd,
+ .magics = BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/superblocks/drbdproxy_datalog.c b/libblkid/src/superblocks/drbdproxy_datalog.c
new file mode 100644
index 0000000..afe4725
--- /dev/null
+++ b/libblkid/src/superblocks/drbdproxy_datalog.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 by Philipp Marek <philipp.marek@linbit.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+
+struct log_header_t {
+ uint64_t magic;
+ uint64_t version;
+
+ unsigned char uuid[16];
+
+ uint64_t flags;
+} __attribute__((packed));
+
+
+static int probe_drbdproxy_datalog(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct log_header_t *lh;
+
+ lh = (struct log_header_t *) blkid_probe_get_buffer(pr, 0, sizeof(*lh));
+ if (!lh)
+ return -1;
+
+ blkid_probe_set_uuid(pr, lh->uuid);
+ blkid_probe_sprintf_version(pr, "v%jd", le64_to_cpu(lh->version));
+
+ return 0;
+}
+
+const struct blkid_idinfo drbdproxy_datalog_idinfo =
+{
+ .name = "drbdproxy_datalog",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_drbdproxy_datalog,
+ .minsz = 16*1024,
+ .magics =
+ {
+ { .magic = "DRBDdlh*", .len = 8, .sboff = 0, .kboff = 0 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/exfat.c b/libblkid/src/superblocks/exfat.c
new file mode 100644
index 0000000..215c671
--- /dev/null
+++ b/libblkid/src/superblocks/exfat.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2010 Andrew Nayenko <resver@gmail.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include "superblocks.h"
+
+struct exfat_super_block {
+ uint8_t jump[3];
+ uint8_t oem_name[8];
+ uint8_t __unused1[53];
+ uint64_t block_start;
+ uint64_t block_count;
+ uint32_t fat_block_start;
+ uint32_t fat_block_count;
+ uint32_t cluster_block_start;
+ uint32_t cluster_count;
+ uint32_t rootdir_cluster;
+ uint8_t volume_serial[4];
+ struct {
+ uint8_t minor;
+ uint8_t major;
+ } version;
+ uint16_t volume_state;
+ uint8_t block_bits;
+ uint8_t bpc_bits;
+ uint8_t fat_count;
+ uint8_t drive_no;
+ uint8_t allocated_percent;
+} __attribute__((__packed__));
+
+struct exfat_entry_label {
+ uint8_t type;
+ uint8_t length;
+ uint8_t name[30];
+} __attribute__((__packed__));
+
+#define BLOCK_SIZE(sb) (1 << (sb)->block_bits)
+#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits)
+#define EXFAT_FIRST_DATA_CLUSTER 2
+#define EXFAT_LAST_DATA_CLUSTER 0xffffff6
+#define EXFAT_ENTRY_SIZE 32
+
+#define EXFAT_ENTRY_EOD 0x00
+#define EXFAT_ENTRY_LABEL 0x83
+
+static blkid_loff_t block_to_offset(const struct exfat_super_block *sb,
+ blkid_loff_t block)
+{
+ return (blkid_loff_t) block << sb->block_bits;
+}
+
+static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb,
+ uint32_t cluster)
+{
+ return le32_to_cpu(sb->cluster_block_start) +
+ ((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER)
+ << sb->bpc_bits);
+}
+
+static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb,
+ uint32_t cluster)
+{
+ return block_to_offset(sb, cluster_to_block(sb, cluster));
+}
+
+static uint32_t next_cluster(blkid_probe pr,
+ const struct exfat_super_block *sb, uint32_t cluster)
+{
+ uint32_t *next;
+ blkid_loff_t fat_offset;
+
+ fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start))
+ + (blkid_loff_t) cluster * sizeof(cluster);
+ next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset,
+ sizeof(uint32_t));
+ if (!next)
+ return 0;
+ return le32_to_cpu(*next);
+}
+
+static struct exfat_entry_label *find_label(blkid_probe pr,
+ const struct exfat_super_block *sb)
+{
+ uint32_t cluster = le32_to_cpu(sb->rootdir_cluster);
+ blkid_loff_t offset = cluster_to_offset(sb, cluster);
+ uint8_t *entry;
+
+ for (;;) {
+ entry = (uint8_t *) blkid_probe_get_buffer(pr, offset,
+ EXFAT_ENTRY_SIZE);
+ if (!entry)
+ return NULL;
+ if (entry[0] == EXFAT_ENTRY_EOD)
+ return NULL;
+ if (entry[0] == EXFAT_ENTRY_LABEL)
+ return (struct exfat_entry_label *) entry;
+ offset += EXFAT_ENTRY_SIZE;
+ if (offset % CLUSTER_SIZE(sb) == 0) {
+ cluster = next_cluster(pr, sb, cluster);
+ if (cluster < EXFAT_FIRST_DATA_CLUSTER)
+ return NULL;
+ if (cluster > EXFAT_LAST_DATA_CLUSTER)
+ return NULL;
+ offset = cluster_to_offset(sb, cluster);
+ }
+ }
+}
+
+static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct exfat_super_block *sb;
+ struct exfat_entry_label *label;
+
+ sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block);
+ if (!sb)
+ return -1;
+
+ label = find_label(pr, sb);
+ if (label)
+ blkid_probe_set_utf8label(pr, label->name,
+ min(label->length * 2, 30), BLKID_ENC_UTF16LE);
+
+ blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4,
+ "%02hhX%02hhX-%02hhX%02hhX",
+ sb->volume_serial[3], sb->volume_serial[2],
+ sb->volume_serial[1], sb->volume_serial[0]);
+
+ blkid_probe_sprintf_version(pr, "%u.%u",
+ sb->version.major, sb->version.minor);
+
+ return 0;
+}
+
+const struct blkid_idinfo exfat_idinfo =
+{
+ .name = "exfat",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_exfat,
+ .magics =
+ {
+ { .magic = "EXFAT ", .len = 8, .sboff = 3 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/ext.c b/libblkid/src/superblocks/ext.c
new file mode 100644
index 0000000..eff96a0
--- /dev/null
+++ b/libblkid/src/superblocks/ext.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#include <time.h>
+
+#include "linux_version.h"
+#include "superblocks.h"
+
+struct ext2_super_block {
+ uint32_t s_inodes_count;
+ uint32_t s_blocks_count;
+ uint32_t s_r_blocks_count;
+ uint32_t s_free_blocks_count;
+ uint32_t s_free_inodes_count;
+ uint32_t s_first_data_block;
+ uint32_t s_log_block_size;
+ uint32_t s_dummy3[7];
+ unsigned char s_magic[2];
+ uint16_t s_state;
+ uint16_t s_errors;
+ uint16_t s_minor_rev_level;
+ uint32_t s_lastcheck;
+ uint32_t s_checkinterval;
+ uint32_t s_creator_os;
+ uint32_t s_rev_level;
+ uint16_t s_def_resuid;
+ uint16_t s_def_resgid;
+ uint32_t s_first_ino;
+ uint16_t s_inode_size;
+ uint16_t s_block_group_nr;
+ uint32_t s_feature_compat;
+ uint32_t s_feature_incompat;
+ uint32_t s_feature_ro_compat;
+ unsigned char s_uuid[16];
+ char s_volume_name[16];
+ char s_last_mounted[64];
+ uint32_t s_algorithm_usage_bitmap;
+ uint8_t s_prealloc_blocks;
+ uint8_t s_prealloc_dir_blocks;
+ uint16_t s_reserved_gdt_blocks;
+ uint8_t s_journal_uuid[16];
+ uint32_t s_journal_inum;
+ uint32_t s_journal_dev;
+ uint32_t s_last_orphan;
+ uint32_t s_hash_seed[4];
+ uint8_t s_def_hash_version;
+ uint8_t s_jnl_backup_type;
+ uint16_t s_reserved_word_pad;
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg;
+ uint32_t s_mkfs_time;
+ uint32_t s_jnl_blocks[17];
+ uint32_t s_blocks_count_hi;
+ uint32_t s_r_blocks_count_hi;
+ uint32_t s_free_blocks_hi;
+ uint16_t s_min_extra_isize;
+ uint16_t s_want_extra_isize;
+ uint32_t s_flags;
+ uint16_t s_raid_stride;
+ uint16_t s_mmp_interval;
+ uint64_t s_mmp_block;
+ uint32_t s_raid_stripe_width;
+ uint32_t s_reserved[163];
+} __attribute__((packed));
+
+/* magic string */
+#define EXT_SB_MAGIC "\123\357"
+/* supper block offset */
+#define EXT_SB_OFF 0x400
+/* supper block offset in kB */
+#define EXT_SB_KBOFF (EXT_SB_OFF >> 10)
+/* magic string offset within super block */
+#define EXT_MAG_OFF 0x38
+
+
+
+/* for s_flags */
+#define EXT2_FLAGS_TEST_FILESYS 0x0004
+
+/* for s_feature_compat */
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+
+/* for s_feature_ro_compat */
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
+
+/* for s_feature_incompat */
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+ EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP
+#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP
+
+#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+ EXT3_FEATURE_INCOMPAT_RECOVER| \
+ EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP
+#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP
+
+/*
+ * Check to see if a filesystem is in /proc/filesystems.
+ * Returns 1 if found, 0 if not
+ */
+static int fs_proc_check(const char *fs_name)
+{
+ FILE *f;
+ char buf[80], *cp, *t;
+
+ f = fopen("/proc/filesystems", "r");
+ if (!f)
+ return 0;
+ while (!feof(f)) {
+ if (!fgets(buf, sizeof(buf), f))
+ break;
+ cp = buf;
+ if (!isspace(*cp)) {
+ while (*cp && !isspace(*cp))
+ cp++;
+ }
+ while (*cp && isspace(*cp))
+ cp++;
+ if ((t = strchr(cp, '\n')) != NULL)
+ *t = 0;
+ if ((t = strchr(cp, '\t')) != NULL)
+ *t = 0;
+ if ((t = strchr(cp, ' ')) != NULL)
+ *t = 0;
+ if (!strcmp(fs_name, cp)) {
+ fclose(f);
+ return 1;
+ }
+ }
+ fclose(f);
+ return (0);
+}
+
+/*
+ * Check to see if a filesystem is available as a module
+ * Returns 1 if found, 0 if not
+ */
+static int check_for_modules(const char *fs_name)
+{
+#ifdef __linux__
+ struct utsname uts;
+ FILE *f;
+ char buf[1024], *cp;
+ int namesz;
+
+ if (uname(&uts))
+ return 0;
+ snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
+
+ f = fopen(buf, "r");
+ if (!f)
+ return 0;
+
+ namesz = strlen(fs_name);
+
+ while (!feof(f)) {
+ if (!fgets(buf, sizeof(buf), f))
+ break;
+ if ((cp = strchr(buf, ':')) != NULL)
+ *cp = 0;
+ else
+ continue;
+ if ((cp = strrchr(buf, '/')) == NULL)
+ continue;
+ cp++;
+
+ if (!strncmp(cp, fs_name, namesz) &&
+ (!strcmp(cp + namesz, ".ko") ||
+ !strcmp(cp + namesz, ".ko.gz"))) {
+ fclose(f);
+ return 1;
+ }
+ }
+ fclose(f);
+#endif /* __linux__ */
+ return 0;
+}
+
+/*
+ * Starting in 2.6.29, ext4 can be used to support filesystems
+ * without a journal.
+ */
+#define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
+
+static int system_supports_ext2(void)
+{
+ static time_t last_check = 0;
+ static int ret = -1;
+ time_t now = time(0);
+
+ if (ret != -1 || (now - last_check) < 5)
+ return ret;
+ last_check = now;
+ ret = (fs_proc_check("ext2") || check_for_modules("ext2"));
+ return ret;
+}
+
+static int system_supports_ext4(void)
+{
+ static time_t last_check = 0;
+ static int ret = -1;
+ time_t now = time(0);
+
+ if (ret != -1 || (now - last_check) < 5)
+ return ret;
+ last_check = now;
+ ret = (fs_proc_check("ext4") || check_for_modules("ext4"));
+ return ret;
+}
+
+static int system_supports_ext4dev(void)
+{
+ static time_t last_check = 0;
+ static int ret = -1;
+ time_t now = time(0);
+
+ if (ret != -1 || (now - last_check) < 5)
+ return ret;
+ last_check = now;
+ ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev"));
+ return ret;
+}
+
+static int system_supports_ext4_ext2(void)
+{
+#ifdef __linux__
+ return get_linux_version() >= EXT4_SUPPORTS_EXT2;
+#else
+ return 0;
+#endif
+}
+/*
+ * reads superblock and returns:
+ * fc = feature_compat
+ * fi = feature_incompat
+ * frc = feature_ro_compat
+ */
+static struct ext2_super_block *ext_get_super(
+ blkid_probe pr, uint32_t *fc, uint32_t *fi, uint32_t *frc)
+{
+ struct ext2_super_block *es;
+
+ es = (struct ext2_super_block *)
+ blkid_probe_get_buffer(pr, EXT_SB_OFF, 0x200);
+ if (!es)
+ return NULL;
+ if (fc)
+ *fc = le32_to_cpu(es->s_feature_compat);
+ if (fi)
+ *fi = le32_to_cpu(es->s_feature_incompat);
+ if (frc)
+ *frc = le32_to_cpu(es->s_feature_ro_compat);
+
+ return es;
+}
+
+static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+ DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n",
+ le32_to_cpu(es->s_feature_compat),
+ le32_to_cpu(es->s_feature_incompat),
+ le32_to_cpu(es->s_feature_ro_compat)));
+
+ if (strlen(es->s_volume_name))
+ blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name,
+ sizeof(es->s_volume_name));
+ blkid_probe_set_uuid(pr, es->s_uuid);
+
+ if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
+ blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL");
+
+ if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) &&
+ ((le32_to_cpu(es->s_feature_incompat) & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0))
+ blkid_probe_set_value(pr, "SEC_TYPE",
+ (unsigned char *) "ext2",
+ sizeof("ext2"));
+
+ blkid_probe_sprintf_version(pr, "%u.%u",
+ le32_to_cpu(es->s_rev_level),
+ le16_to_cpu(es->s_minor_rev_level));
+}
+
+
+static int probe_jbd(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct ext2_super_block *es;
+ uint32_t fi;
+
+ es = ext_get_super(pr, NULL, &fi, NULL);
+ if (!es)
+ return -BLKID_ERR_PARAM;
+ if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
+ return -BLKID_ERR_PARAM;
+
+ ext_get_info(pr, 2, es);
+ return 0;
+}
+
+static int probe_ext2(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct ext2_super_block *es;
+ uint32_t fc, frc, fi;
+
+ es = ext_get_super(pr, &fc, &fi, &frc);
+ if (!es)
+ return -BLKID_ERR_PARAM;
+
+ /* Distinguish between ext3 and ext2 */
+ if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
+ return -BLKID_ERR_PARAM;
+
+ /* Any features which ext2 doesn't understand */
+ if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+ (fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
+ return -BLKID_ERR_PARAM;
+
+ /*
+ * If ext2 is not present, but ext4 or ext4dev are, then
+ * disclaim we are ext2
+ */
+ if (!system_supports_ext2() &&
+ (system_supports_ext4() || system_supports_ext4dev()) &&
+ system_supports_ext4_ext2())
+ return -BLKID_ERR_PARAM;
+
+ ext_get_info(pr, 2, es);
+ return 0;
+}
+
+static int probe_ext3(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct ext2_super_block *es;
+ uint32_t fc, frc, fi;
+
+ es = ext_get_super(pr, &fc, &fi, &frc);
+ if (!es)
+ return -BLKID_ERR_PARAM;
+
+ /* ext3 requires journal */
+ if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+ return -BLKID_ERR_PARAM;
+
+ /* Any features which ext3 doesn't understand */
+ if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+ (fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+ return -BLKID_ERR_PARAM;
+
+ ext_get_info(pr, 3, es);
+ return 0;
+}
+
+
+static int probe_ext4dev(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct ext2_super_block *es;
+ uint32_t fc, frc, fi;
+
+ es = ext_get_super(pr, &fc, &fi, &frc);
+ if (!es)
+ return -BLKID_ERR_PARAM;
+
+ /* Distinguish from jbd */
+ if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+ return -BLKID_ERR_PARAM;
+
+ /*
+ * If the filesystem does not have a journal and ext2 and ext4
+ * is not present, then force this to be detected as an
+ * ext4dev filesystem.
+ */
+ if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ !system_supports_ext2() && !system_supports_ext4() &&
+ system_supports_ext4dev() &&
+ system_supports_ext4_ext2())
+ goto force_ext4dev;
+
+ /*
+ * If the filesystem is marked as OK for use by in-development
+ * filesystem code, but ext4dev is not supported, and ext4 is,
+ * then don't call ourselves ext4dev, since we should be
+ * detected as ext4 in that case.
+ *
+ * If the filesystem is marked as in use by production
+ * filesystem, then it can only be used by ext4 and NOT by
+ * ext4dev, so always disclaim we are ext4dev in that case.
+ */
+ if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
+ if (!system_supports_ext4dev() && system_supports_ext4())
+ return -BLKID_ERR_PARAM;
+ } else
+ return -BLKID_ERR_PARAM;
+
+force_ext4dev:
+ ext_get_info(pr, 4, es);
+ return 0;
+}
+
+static int probe_ext4(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct ext2_super_block *es;
+ uint32_t fc, frc, fi;
+
+ es = ext_get_super(pr, &fc, &fi, &frc);
+ if (!es)
+ return -1;
+
+ /* Distinguish from jbd */
+ if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+ return -BLKID_ERR_PARAM;
+
+ /*
+ * If the filesystem does not have a journal and ext2 is not
+ * present, then force this to be detected as an ext2
+ * filesystem.
+ */
+ if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ !system_supports_ext2() && system_supports_ext4() &&
+ system_supports_ext4_ext2())
+ goto force_ext4;
+
+ /* Ext4 has at least one feature which ext3 doesn't understand */
+ if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
+ !(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+ return -BLKID_ERR_PARAM;
+
+force_ext4:
+ /*
+ * If the filesystem is a OK for use by in-development
+ * filesystem code, and ext4dev is supported or ext4 is not
+ * supported, then don't call ourselves ext4, so we can redo
+ * the detection and mark the filesystem as ext4dev.
+ *
+ * If the filesystem is marked as in use by production
+ * filesystem, then it can only be used by ext4 and NOT by
+ * ext4dev.
+ */
+ if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
+ if (system_supports_ext4dev() || !system_supports_ext4())
+ return -BLKID_ERR_PARAM;
+ }
+
+ ext_get_info(pr, 4, es);
+ return 0;
+}
+
+#define BLKID_EXT_MAGICS \
+ { \
+ { \
+ .magic = EXT_SB_MAGIC, \
+ .len = sizeof(EXT_SB_MAGIC) - 1, \
+ .kboff = EXT_SB_KBOFF, \
+ .sboff = EXT_MAG_OFF \
+ }, \
+ { NULL } \
+ }
+
+const struct blkid_idinfo jbd_idinfo =
+{
+ .name = "jbd",
+ .usage = BLKID_USAGE_OTHER,
+ .probefunc = probe_jbd,
+ .magics = BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext2_idinfo =
+{
+ .name = "ext2",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ext2,
+ .magics = BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext3_idinfo =
+{
+ .name = "ext3",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ext3,
+ .magics = BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext4_idinfo =
+{
+ .name = "ext4",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ext4,
+ .magics = BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext4dev_idinfo =
+{
+ .name = "ext4dev",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ext4dev,
+ .magics = BLKID_EXT_MAGICS
+};
+
diff --git a/libblkid/src/superblocks/gfs.c b/libblkid/src/superblocks/gfs.c
new file mode 100644
index 0000000..b2c0163
--- /dev/null
+++ b/libblkid/src/superblocks/gfs.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+/* Common gfs/gfs2 constants: */
+#define GFS_LOCKNAME_LEN 64
+
+/* gfs1 constants: */
+#define GFS_FORMAT_FS 1309
+#define GFS_FORMAT_MULTI 1401
+/* gfs2 constants: */
+#define GFS2_FORMAT_FS 1801
+#define GFS2_FORMAT_MULTI 1900
+
+struct gfs2_meta_header {
+ uint32_t mh_magic;
+ uint32_t mh_type;
+ uint64_t __pad0; /* Was generation number in gfs1 */
+ uint32_t mh_format;
+ uint32_t __pad1; /* Was incarnation number in gfs1 */
+};
+
+struct gfs2_inum {
+ uint64_t no_formal_ino;
+ uint64_t no_addr;
+};
+
+struct gfs2_sb {
+ struct gfs2_meta_header sb_header;
+
+ uint32_t sb_fs_format;
+ uint32_t sb_multihost_format;
+ uint32_t __pad0; /* Was superblock flags in gfs1 */
+
+ uint32_t sb_bsize;
+ uint32_t sb_bsize_shift;
+ uint32_t __pad1; /* Was journal segment size in gfs1 */
+
+ struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
+ struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
+ struct gfs2_inum sb_root_dir;
+
+ char sb_lockproto[GFS_LOCKNAME_LEN];
+ char sb_locktable[GFS_LOCKNAME_LEN];
+
+ struct gfs2_inum __pad3; /* Was quota inode in gfs1 */
+ struct gfs2_inum __pad4; /* Was licence inode in gfs1 */
+ uint8_t sb_uuid[16]; /* The UUID maybe 0 for backwards compat */
+} __attribute__((packed));
+
+static int probe_gfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct gfs2_sb *sbd;
+
+ sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
+ if (!sbd)
+ return -1;
+
+ if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS &&
+ be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI)
+ {
+ if (*sbd->sb_locktable)
+ blkid_probe_set_label(pr,
+ (unsigned char *) sbd->sb_locktable,
+ sizeof(sbd->sb_locktable));
+
+ blkid_probe_set_uuid(pr, sbd->sb_uuid);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct gfs2_sb *sbd;
+
+ sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
+ if (!sbd)
+ return -1;
+
+ if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS &&
+ be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI)
+ {
+ if (*sbd->sb_locktable)
+ blkid_probe_set_label(pr,
+ (unsigned char *) sbd->sb_locktable,
+ sizeof(sbd->sb_locktable));
+ blkid_probe_set_uuid(pr, sbd->sb_uuid);
+ blkid_probe_set_version(pr, "1");
+ return 0;
+ }
+ return -1;
+}
+
+const struct blkid_idinfo gfs_idinfo =
+{
+ .name = "gfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_gfs,
+ .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */
+ .magics =
+ {
+ { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo gfs2_idinfo =
+{
+ .name = "gfs2",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_gfs2,
+ .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */
+ .magics =
+ {
+ { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/hfs.c b/libblkid/src/superblocks/hfs.c
new file mode 100644
index 0000000..6d960e9
--- /dev/null
+++ b/libblkid/src/superblocks/hfs.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 "superblocks.h"
+#include "md5.h"
+
+/* HFS / HFS+ */
+struct hfs_finder_info {
+ uint32_t boot_folder;
+ uint32_t start_app;
+ uint32_t open_folder;
+ uint32_t os9_folder;
+ uint32_t reserved;
+ uint32_t osx_folder;
+ uint8_t id[8];
+} __attribute__((packed));
+
+struct hfs_mdb {
+ uint8_t signature[2];
+ uint32_t cr_date;
+ uint32_t ls_Mod;
+ uint16_t atrb;
+ uint16_t nm_fls;
+ uint16_t vbm_st;
+ uint16_t alloc_ptr;
+ uint16_t nm_al_blks;
+ uint32_t al_blk_size;
+ uint32_t clp_size;
+ uint16_t al_bl_st;
+ uint32_t nxt_cnid;
+ uint16_t free_bks;
+ uint8_t label_len;
+ uint8_t label[27];
+ uint32_t vol_bkup;
+ uint16_t vol_seq_num;
+ uint32_t wr_cnt;
+ uint32_t xt_clump_size;
+ uint32_t ct_clump_size;
+ uint16_t num_root_dirs;
+ uint32_t file_count;
+ uint32_t dir_count;
+ struct hfs_finder_info finder_info;
+ uint8_t embed_sig[2];
+ uint16_t embed_startblock;
+ uint16_t embed_blockcount;
+} __attribute__((packed));
+
+
+#define HFS_NODE_LEAF 0xff
+#define HFSPLUS_POR_CNID 1
+
+struct hfsplus_bnode_descriptor {
+ uint32_t next;
+ uint32_t prev;
+ uint8_t type;
+ uint8_t height;
+ uint16_t num_recs;
+ uint16_t reserved;
+} __attribute__((packed));
+
+struct hfsplus_bheader_record {
+ uint16_t depth;
+ uint32_t root;
+ uint32_t leaf_count;
+ uint32_t leaf_head;
+ uint32_t leaf_tail;
+ uint16_t node_size;
+} __attribute__((packed));
+
+struct hfsplus_catalog_key {
+ uint16_t key_len;
+ uint32_t parent_id;
+ uint16_t unicode_len;
+ uint8_t unicode[255 * 2];
+} __attribute__((packed));
+
+struct hfsplus_extent {
+ uint32_t start_block;
+ uint32_t block_count;
+} __attribute__((packed));
+
+#define HFSPLUS_EXTENT_COUNT 8
+struct hfsplus_fork {
+ uint64_t total_size;
+ uint32_t clump_size;
+ uint32_t total_blocks;
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+} __attribute__((packed));
+
+struct hfsplus_vol_header {
+ uint8_t signature[2];
+ uint16_t version;
+ uint32_t attributes;
+ uint32_t last_mount_vers;
+ uint32_t reserved;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ uint32_t checked_date;
+ uint32_t file_count;
+ uint32_t folder_count;
+ uint32_t blocksize;
+ uint32_t total_blocks;
+ uint32_t free_blocks;
+ uint32_t next_alloc;
+ uint32_t rsrc_clump_sz;
+ uint32_t data_clump_sz;
+ uint32_t next_cnid;
+ uint32_t write_count;
+ uint64_t encodings_bmp;
+ struct hfs_finder_info finder_info;
+ struct hfsplus_fork alloc_file;
+ struct hfsplus_fork ext_file;
+ struct hfsplus_fork cat_file;
+ struct hfsplus_fork attr_file;
+ struct hfsplus_fork start_file;
+} __attribute__((packed));
+
+#define HFSPLUS_SECTOR_SIZE 512
+
+static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len)
+{
+ static unsigned char const hash_init[MD5LENGTH] = {
+ 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
+ 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
+ };
+ unsigned char uuid[MD5LENGTH];
+ struct MD5Context md5c;
+
+ if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0)
+ return -1;
+ MD5Init(&md5c);
+ MD5Update(&md5c, hash_init, MD5LENGTH);
+ MD5Update(&md5c, hfs_info, len);
+ MD5Final(uuid, &md5c);
+ uuid[6] = 0x30 | (uuid[6] & 0x0f);
+ uuid[8] = 0x80 | (uuid[8] & 0x3f);
+ return blkid_probe_set_uuid(pr, uuid);
+}
+
+static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct hfs_mdb *hfs;
+
+ hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
+ if (!hfs)
+ return -1;
+
+ if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
+ (memcmp(hfs->embed_sig, "HX", 2) == 0))
+ return 1; /* Not hfs, but an embedded HFS+ */
+
+ hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id));
+
+ blkid_probe_set_label(pr, hfs->label, hfs->label_len);
+ return 0;
+}
+
+static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+ struct hfsplus_bnode_descriptor *descr;
+ struct hfsplus_bheader_record *bnode;
+ struct hfsplus_catalog_key *key;
+ struct hfsplus_vol_header *hfsplus;
+ struct hfs_mdb *sbd;
+ unsigned int alloc_block_size;
+ unsigned int alloc_first_block;
+ unsigned int embed_first_block;
+ unsigned int off = 0;
+ unsigned int blocksize;
+ unsigned int cat_block;
+ unsigned int ext_block_start;
+ unsigned int ext_block_count;
+ unsigned int record_count;
+ unsigned int leaf_node_head;
+ unsigned int leaf_node_count;
+ unsigned int leaf_node_size;
+ unsigned int leaf_block;
+ int ext;
+ uint64_t leaf_off;
+ unsigned char *buf;
+
+ sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
+ if (!sbd)
+ return -1;
+
+ /* Check for a HFS+ volume embedded in a HFS volume */
+ if (memcmp(sbd->signature, "BD", 2) == 0) {
+ if ((memcmp(sbd->embed_sig, "H+", 2) != 0) &&
+ (memcmp(sbd->embed_sig, "HX", 2) != 0))
+ /* This must be an HFS volume, so fail */
+ return 1;
+
+ alloc_block_size = be32_to_cpu(sbd->al_blk_size);
+ alloc_first_block = be16_to_cpu(sbd->al_bl_st);
+ embed_first_block = be16_to_cpu(sbd->embed_startblock);
+ off = (alloc_first_block * 512) +
+ (embed_first_block * alloc_block_size);
+
+ buf = blkid_probe_get_buffer(pr,
+ off + (mag->kboff * 1024),
+ sizeof(struct hfsplus_vol_header));
+ hfsplus = (struct hfsplus_vol_header *) buf;
+
+ } else
+ hfsplus = blkid_probe_get_sb(pr, mag,
+ struct hfsplus_vol_header);
+
+ if (!hfsplus)
+ return -1;
+
+ if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
+ (memcmp(hfsplus->signature, "HX", 2) != 0))
+ return 1;
+
+ hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id));
+
+ blocksize = be32_to_cpu(hfsplus->blocksize);
+ if (blocksize < HFSPLUS_SECTOR_SIZE)
+ return -1;
+
+ memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+ cat_block = be32_to_cpu(extents[0].start_block);
+
+ buf = blkid_probe_get_buffer(pr,
+ off + ((blkid_loff_t) cat_block * blocksize), 0x2000);
+ if (!buf)
+ return 0;
+
+ bnode = (struct hfsplus_bheader_record *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ leaf_node_head = be32_to_cpu(bnode->leaf_head);
+ leaf_node_size = be16_to_cpu(bnode->node_size);
+ leaf_node_count = be32_to_cpu(bnode->leaf_count);
+ if (leaf_node_count == 0)
+ return 0;
+
+ leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
+
+ /* get physical location */
+ for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
+ ext_block_start = be32_to_cpu(extents[ext].start_block);
+ ext_block_count = be32_to_cpu(extents[ext].block_count);
+ if (ext_block_count == 0)
+ return 0;
+
+ /* this is our extent */
+ if (leaf_block < ext_block_count)
+ break;
+
+ leaf_block -= ext_block_count;
+ }
+ if (ext == HFSPLUS_EXTENT_COUNT)
+ return 0;
+
+ leaf_off = (ext_block_start + leaf_block) * blocksize;
+
+ buf = blkid_probe_get_buffer(pr,
+ (blkid_loff_t) off + leaf_off,
+ leaf_node_size);
+ if (!buf)
+ return 0;
+
+ descr = (struct hfsplus_bnode_descriptor *) buf;
+ record_count = be16_to_cpu(descr->num_recs);
+ if (record_count == 0)
+ return 0;
+
+ if (descr->type != HFS_NODE_LEAF)
+ return 0;
+
+ key = (struct hfsplus_catalog_key *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
+ return 0;
+
+ blkid_probe_set_utf8label(pr, key->unicode,
+ be16_to_cpu(key->unicode_len) * 2,
+ BLKID_ENC_UTF16BE);
+ return 0;
+}
+
+const struct blkid_idinfo hfs_idinfo =
+{
+ .name = "hfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_hfs,
+ .flags = BLKID_IDINFO_TOLERANT,
+ .magics =
+ {
+ { .magic = "BD", .len = 2, .kboff = 1 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo hfsplus_idinfo =
+{
+ .name = "hfsplus",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_hfsplus,
+ .magics =
+ {
+ { .magic = "BD", .len = 2, .kboff = 1 },
+ { .magic = "H+", .len = 2, .kboff = 1 },
+ { .magic = "HX", .len = 2, .kboff = 1 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/highpoint_raid.c b/libblkid/src/superblocks/highpoint_raid.c
new file mode 100644
index 0000000..0b41344
--- /dev/null
+++ b/libblkid/src/superblocks/highpoint_raid.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct hpt45x_metadata {
+ uint32_t magic;
+};
+
+#define HPT45X_MAGIC_OK 0x5a7816f3
+#define HPT45X_MAGIC_BAD 0x5a7816fd
+
+static int probe_highpoint45x(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct hpt45x_metadata *hpt;
+ uint64_t off;
+ uint32_t magic;
+
+ if (pr->size < 0x10000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200) - 11) * 0x200;
+ hpt = (struct hpt45x_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct hpt45x_metadata));
+ if (!hpt)
+ return -1;
+ magic = le32_to_cpu(hpt->magic);
+ if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(hpt->magic),
+ (unsigned char *) &hpt->magic))
+ return -1;
+ return 0;
+}
+
+static int probe_highpoint37x(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+ return 0;
+}
+
+
+const struct blkid_idinfo highpoint45x_idinfo = {
+ .name = "hpt45x_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_highpoint45x,
+ .magics = BLKID_NONE_MAGIC
+};
+
+const struct blkid_idinfo highpoint37x_idinfo = {
+ .name = "hpt37x_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_highpoint37x,
+ .magics = {
+ /*
+ * Superblok offset: 4608 bytes (9 sectors)
+ * Magic string offset within superblock: 32 bytes
+ *
+ * kboff = (4608 + 32) / 1024
+ * sboff = (4608 + 32) % kboff
+ */
+ { .magic = "\xf0\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 },
+ { .magic = "\xfd\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 },
+ { NULL }
+ }
+};
+
+
diff --git a/libblkid/src/superblocks/hpfs.c b/libblkid/src/superblocks/hpfs.c
new file mode 100644
index 0000000..f9b851a
--- /dev/null
+++ b/libblkid/src/superblocks/hpfs.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct hpfs_boot_block
+{
+ uint8_t jmp[3];
+ uint8_t oem_id[8];
+ uint8_t bytes_per_sector[2];
+ uint8_t sectors_per_cluster;
+ uint8_t n_reserved_sectors[2];
+ uint8_t n_fats;
+ uint8_t n_rootdir_entries[2];
+ uint8_t n_sectors_s[2];
+ uint8_t media_byte;
+ uint16_t sectors_per_fat;
+ uint16_t sectors_per_track;
+ uint16_t heads_per_cyl;
+ uint32_t n_hidden_sectors;
+ uint32_t n_sectors_l;
+ uint8_t drive_number;
+ uint8_t mbz;
+ uint8_t sig_28h;
+ uint8_t vol_serno[4];
+ uint8_t vol_label[11];
+ uint8_t sig_hpfs[8];
+ uint8_t pad[448];
+ uint8_t magic[2];
+} __attribute__((packed));
+
+struct hpfs_super_block
+{
+ uint8_t magic[4];
+ uint8_t magic1[4];
+ uint8_t version;
+} __attribute__((packed));
+
+struct hpfs_spare_super
+{
+ uint8_t magic[4];
+ uint8_t magic1[4];
+} __attribute__((packed));
+
+
+#define HPFS_SB_OFFSET 0x2000
+#define HPFS_SBSPARE_OFFSET 0x2200
+
+static int probe_hpfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct hpfs_super_block *hs;
+ struct hpfs_spare_super *hss;
+ struct hpfs_boot_block *hbb;
+ uint8_t version;
+
+ /* super block */
+ hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block);
+ if (!hs)
+ return -1;
+ version = hs->version;
+
+ /* spare super block */
+ hss = (struct hpfs_spare_super *)
+ blkid_probe_get_buffer(pr,
+ HPFS_SBSPARE_OFFSET,
+ sizeof(struct hpfs_spare_super));
+ if (!hss)
+ return -1;
+ if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0)
+ return -1;
+
+ /* boot block (with UUID and LABEL) */
+ hbb = (struct hpfs_boot_block *)
+ blkid_probe_get_buffer(pr,
+ 0,
+ sizeof(struct hpfs_boot_block));
+ if (!hbb)
+ return -1;
+ if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 &&
+ memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 &&
+ hbb->sig_28h == 0x28) {
+ blkid_probe_set_label(pr, hbb->vol_label, sizeof(hbb->vol_label));
+ blkid_probe_sprintf_uuid(pr,
+ hbb->vol_serno, sizeof(hbb->vol_serno),
+ "%02X%02X-%02X%02X",
+ hbb->vol_serno[3], hbb->vol_serno[2],
+ hbb->vol_serno[1], hbb->vol_serno[0]);
+ }
+ blkid_probe_sprintf_version(pr, "%u", version);
+
+ return 0;
+}
+
+const struct blkid_idinfo hpfs_idinfo =
+{
+ .name = "hpfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_hpfs,
+ .magics =
+ {
+ {
+ .magic = "\x49\xe8\x95\xf9",
+ .len = 4,
+ .kboff = (HPFS_SB_OFFSET >> 10)
+ },
+ { NULL }
+ }
+};
+
+
diff --git a/libblkid/src/superblocks/iso9660.c b/libblkid/src/superblocks/iso9660.c
new file mode 100644
index 0000000..f7d2b76
--- /dev/null
+++ b/libblkid/src/superblocks/iso9660.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired also by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct iso9660_date {
+ unsigned char year[4];
+ unsigned char month[2];
+ unsigned char day[2];
+ unsigned char hour[2];
+ unsigned char minute[2];
+ unsigned char second[2];
+ unsigned char hundredth[2];
+ unsigned char offset;
+} __attribute__ ((packed));
+
+/* PVD - Primary volume descriptor */
+struct iso_volume_descriptor {
+ unsigned char vd_type;
+ unsigned char vd_id[5];
+ unsigned char vd_version;
+ unsigned char flags;
+ unsigned char system_id[32];
+ unsigned char volume_id[32];
+ unsigned char unused[8];
+ unsigned char space_size[8];
+ unsigned char escape_sequences[8];
+ unsigned char unused1[717];
+ struct iso9660_date created;
+ struct iso9660_date modified;
+} __attribute__((packed));
+
+#define ISO_SUPERBLOCK_OFFSET 0x8000
+#define ISO_SECTOR_SIZE 0x800
+#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
+#define ISO_VD_SUPPLEMENTARY 0x2
+#define ISO_VD_END 0xff
+#define ISO_VD_MAX 16
+
+struct high_sierra_volume_descriptor {
+ unsigned char foo[8];
+ unsigned char type;
+ unsigned char id[5];
+ unsigned char version;
+ unsigned char unused1;
+ unsigned char system_id[32];
+ unsigned char volume_id[32];
+} __attribute__((packed));
+
+/* returns 1 if the begin of @ascii is equal to @utf16 string.
+ */
+static int ascii_eq_utf16be(unsigned char *ascii,
+ unsigned char *utf16, size_t len)
+{
+ size_t a, u;
+
+ for (a = 0, u = 0; u < len; a++, u += 2) {
+ if (utf16[u] != 0x0 || ascii[a] != utf16[u + 1])
+ return 0;
+ }
+ return 1;
+}
+
+/* old High Sierra format */
+static int probe_iso9660_hsfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct high_sierra_volume_descriptor *iso;
+
+ iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor);
+ if (!iso)
+ return -1;
+
+ blkid_probe_set_version(pr, "High Sierra");
+ blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id));
+ return 0;
+}
+
+static int probe_iso9660_set_uuid (blkid_probe pr, const struct iso9660_date *date)
+{
+ unsigned char buffer[16];
+ unsigned int i, zeros = 0;
+
+ buffer[0] = date->year[0];
+ buffer[1] = date->year[1];
+ buffer[2] = date->year[2];
+ buffer[3] = date->year[3];
+ buffer[4] = date->month[0];
+ buffer[5] = date->month[1];
+ buffer[6] = date->day[0];
+ buffer[7] = date->day[1];
+ buffer[8] = date->hour[0];
+ buffer[9] = date->hour[1];
+ buffer[10] = date->minute[0];
+ buffer[11] = date->minute[1];
+ buffer[12] = date->second[0];
+ buffer[13] = date->second[1];
+ buffer[14] = date->hundredth[0];
+ buffer[15] = date->hundredth[1];
+
+ /* count the number of zeros ('0') in the date buffer */
+ for (i = 0, zeros = 0; i < sizeof(buffer); i++)
+ if (buffer[i] == '0')
+ zeros++;
+
+ /* due to the iso9660 standard if all date fields are '0' and offset is 0, the date is unset */
+ if (zeros == sizeof(buffer) && date->offset == 0)
+ return 0;
+
+ /* generate an UUID using this date and return success */
+ blkid_probe_sprintf_uuid (pr, buffer, sizeof(buffer),
+ "%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
+ buffer[0], buffer[1], buffer[2], buffer[3],
+ buffer[4], buffer[5],
+ buffer[6], buffer[7],
+ buffer[8], buffer[9],
+ buffer[10], buffer[11],
+ buffer[12], buffer[13],
+ buffer[14], buffer[15]);
+
+ return 1;
+}
+
+/* iso9660 [+ Microsoft Joliet Extension] */
+static int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct iso_volume_descriptor *iso;
+ unsigned char label[32];
+ int i;
+ int off;
+
+ if (strcmp(mag->magic, "CDROM") == 0)
+ return probe_iso9660_hsfs(pr, mag);
+
+ iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor);
+ if (!iso)
+ return -1;
+
+ memcpy(label, iso->volume_id, sizeof(label));
+
+ /* create an UUID using the modified/created date */
+ if (! probe_iso9660_set_uuid(pr, &iso->modified))
+ probe_iso9660_set_uuid(pr, &iso->created);
+
+ /* Joliet Extension */
+ off = ISO_VD_OFFSET;
+ for (i = 0; i < ISO_VD_MAX; i++) {
+ iso = (struct iso_volume_descriptor *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct iso_volume_descriptor));
+
+ if (iso == NULL || iso->vd_type == ISO_VD_END)
+ break;
+ if (iso->vd_type != ISO_VD_SUPPLEMENTARY)
+ continue;
+
+ if (memcmp(iso->escape_sequences, "%/@", 3) == 0 ||
+ memcmp(iso->escape_sequences, "%/C", 3) == 0 ||
+ memcmp(iso->escape_sequences, "%/E", 3) == 0) {
+
+ blkid_probe_set_version(pr, "Joliet Extension");
+
+ /* Is the Joliet (UTF16BE) label equal to the label in
+ * the PVD? If yes, use PVD label. The Jolied version
+ * of the label could be trimed (because UTF16..).
+ */
+ if (ascii_eq_utf16be(label, iso->volume_id, 32))
+ break;
+
+ blkid_probe_set_utf8label(pr,
+ iso->volume_id,
+ sizeof(iso->volume_id),
+ BLKID_ENC_UTF16BE);
+ goto has_label;
+ }
+ off += ISO_SECTOR_SIZE;
+ }
+
+ /* Joliet not found, let use standard iso label */
+ blkid_probe_set_label(pr, label, sizeof(label));
+
+has_label:
+ return 0;
+}
+
+const struct blkid_idinfo iso9660_idinfo =
+{
+ .name = "iso9660",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_iso9660,
+ .flags = BLKID_IDINFO_TOLERANT,
+ .magics =
+ {
+ { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 },
+ { .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/isw_raid.c b/libblkid/src/superblocks/isw_raid.c
new file mode 100644
index 0000000..755c1b6
--- /dev/null
+++ b/libblkid/src/superblocks/isw_raid.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct isw_metadata {
+ uint8_t sig[32];
+ uint32_t check_sum;
+ uint32_t mpb_size;
+ uint32_t family_num;
+ uint32_t generation_num;
+};
+
+#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. "
+
+
+static int probe_iswraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t off;
+ struct isw_metadata *isw;
+
+ if (pr->size < 0x10000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200) - 2) * 0x200;
+ isw = (struct isw_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct isw_metadata));
+ if (!isw)
+ return -1;
+ if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
+ return -1;
+ if (blkid_probe_sprintf_version(pr, "%6s",
+ &isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(isw->sig),
+ (unsigned char *) isw->sig))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo iswraid_idinfo = {
+ .name = "isw_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_iswraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/jfs.c b/libblkid/src/superblocks/jfs.c
new file mode 100644
index 0000000..78c018c
--- /dev/null
+++ b/libblkid/src/superblocks/jfs.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct jfs_super_block {
+ unsigned char js_magic[4];
+ uint32_t js_version;
+ uint64_t js_size;
+ uint32_t js_bsize; /* 4: aggregate block size in bytes */
+ uint16_t js_l2bsize; /* 2: log2 of s_bsize */
+ uint16_t js_l2bfactor; /* 2: log2(s_bsize/hardware block size) */
+ uint32_t js_pbsize; /* 4: hardware/LVM block size in bytes */
+ uint16_t js_l2pbsize; /* 2: log2 of s_pbsize */
+ uint16_t js_pad; /* 2: padding necessary for alignment */
+ uint32_t js_dummy2[26];
+ unsigned char js_uuid[16];
+ unsigned char js_label[16];
+ unsigned char js_loguuid[16];
+};
+
+static int probe_jfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct jfs_super_block *js;
+
+ js = blkid_probe_get_sb(pr, mag, struct jfs_super_block);
+ if (!js)
+ return -1;
+ if (le32_to_cpu(js->js_bsize) != (1U << le16_to_cpu(js->js_l2bsize)))
+ return 1;
+ if (le32_to_cpu(js->js_pbsize) != (1U << le16_to_cpu(js->js_l2pbsize)))
+ return 1;
+ if ((le16_to_cpu(js->js_l2bsize) - le16_to_cpu(js->js_l2pbsize)) !=
+ le16_to_cpu(js->js_l2bfactor))
+ return 1;
+
+ if (strlen((char *) js->js_label))
+ blkid_probe_set_label(pr, js->js_label, sizeof(js->js_label));
+ blkid_probe_set_uuid(pr, js->js_uuid);
+ return 0;
+}
+
+
+const struct blkid_idinfo jfs_idinfo =
+{
+ .name = "jfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_jfs,
+ .minsz = 16 * 1024 * 1024,
+ .magics =
+ {
+ { .magic = "JFS1", .len = 4, .kboff = 32 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/jmicron_raid.c b/libblkid/src/superblocks/jmicron_raid.c
new file mode 100644
index 0000000..c708078
--- /dev/null
+++ b/libblkid/src/superblocks/jmicron_raid.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct jm_metadata {
+ int8_t signature[2];
+ uint8_t minor_version;
+ uint8_t major_version;
+ uint16_t checksum;
+};
+
+#define JM_SIGNATURE "JM"
+
+static int probe_jmraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t off;
+ struct jm_metadata *jm;
+
+ if (pr->size < 0x10000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200) - 1) * 0x200;
+ jm = (struct jm_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct jm_metadata));
+ if (!jm)
+ return -1;
+ if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0)
+ return -1;
+ if (blkid_probe_sprintf_version(pr, "%u.%u",
+ jm->major_version, jm->minor_version) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(jm->signature),
+ (unsigned char *) jm->signature))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo jmraid_idinfo = {
+ .name = "jmicron_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_jmraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/linux_raid.c b/libblkid/src/superblocks/linux_raid.c
new file mode 100644
index 0000000..a3f9d67
--- /dev/null
+++ b/libblkid/src/superblocks/linux_raid.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct mdp0_super_block {
+ uint32_t md_magic;
+ uint32_t major_version;
+ uint32_t minor_version;
+ uint32_t patch_version;
+ uint32_t gvalid_words;
+ uint32_t set_uuid0;
+ uint32_t ctime;
+ uint32_t level;
+ uint32_t size;
+ uint32_t nr_disks;
+ uint32_t raid_disks;
+ uint32_t md_minor;
+ uint32_t not_persistent;
+ uint32_t set_uuid1;
+ uint32_t set_uuid2;
+ uint32_t set_uuid3;
+};
+
+/*
+ * Version-1, little-endian.
+ */
+struct mdp1_super_block {
+ /* constant array information - 128 bytes */
+ uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */
+ uint32_t major_version; /* 1 */
+ uint32_t feature_map; /* 0 for now */
+ uint32_t pad0; /* always set to 0 when writing */
+
+ uint8_t set_uuid[16]; /* user-space generated. */
+ unsigned char set_name[32]; /* set and interpreted by user-space */
+
+ uint64_t ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/
+ uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5 */
+ uint32_t layout; /* only for raid5 currently */
+ uint64_t size; /* used size of component devices, in 512byte sectors */
+
+ uint32_t chunksize; /* in 512byte sectors */
+ uint32_t raid_disks;
+ uint32_t bitmap_offset; /* sectors after start of superblock that bitmap starts
+ * NOTE: signed, so bitmap can be before superblock
+ * only meaningful of feature_map[0] is set.
+ */
+
+ /* These are only valid with feature bit '4' */
+ uint32_t new_level; /* new level we are reshaping to */
+ uint64_t reshape_position; /* next address in array-space for reshape */
+ uint32_t delta_disks; /* change in number of raid_disks */
+ uint32_t new_layout; /* new layout */
+ uint32_t new_chunk; /* new chunk size (bytes) */
+ uint8_t pad1[128-124]; /* set to 0 when written */
+
+ /* constant this-device information - 64 bytes */
+ uint64_t data_offset; /* sector start of data, often 0 */
+ uint64_t data_size; /* sectors in this device that can be used for data */
+ uint64_t super_offset; /* sector start of this superblock */
+ uint64_t recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
+ uint32_t dev_number; /* permanent identifier of this device - not role in raid */
+ uint32_t cnt_corrected_read; /* number of read errors that were corrected by re-writing */
+ uint8_t device_uuid[16]; /* user-space setable, ignored by kernel */
+ uint8_t devflags; /* per-device flags. Only one defined...*/
+ uint8_t pad2[64-57]; /* set to 0 when writing */
+
+ /* array state information - 64 bytes */
+ uint64_t utime; /* 40 bits second, 24 btes microseconds */
+ uint64_t events; /* incremented when superblock updated */
+ uint64_t resync_offset; /* data before this offset (from data_offset) known to be in sync */
+ uint32_t sb_csum; /* checksum up to dev_roles[max_dev] */
+ uint32_t max_dev; /* size of dev_roles[] array to consider */
+ uint8_t pad3[64-32]; /* set to 0 when writing */
+
+ /* device state information. Indexed by dev_number.
+ * 2 bytes per device
+ * Note there are no per-device state flags. State information is rolled
+ * into the 'roles' value. If a device is spare or faulty, then it doesn't
+ * have a meaningful role.
+ */
+ uint16_t dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
+};
+
+
+#define MD_RESERVED_BYTES 0x10000
+#define MD_SB_MAGIC 0xa92b4efc
+
+static int probe_raid0(blkid_probe pr, blkid_loff_t off)
+{
+ struct mdp0_super_block *mdp0;
+ union {
+ uint32_t ints[4];
+ uint8_t bytes[16];
+ } uuid;
+ uint32_t ma, mi, pa;
+ uint64_t size;
+
+ if (pr->size < MD_RESERVED_BYTES)
+ return -1;
+ mdp0 = (struct mdp0_super_block *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct mdp0_super_block));
+ if (!mdp0)
+ return -1;
+
+ memset(uuid.ints, 0, sizeof(uuid.ints));
+
+ if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
+ uuid.ints[0] = swab32(mdp0->set_uuid0);
+ if (le32_to_cpu(mdp0->minor_version) >= 90) {
+ uuid.ints[1] = swab32(mdp0->set_uuid1);
+ uuid.ints[2] = swab32(mdp0->set_uuid2);
+ uuid.ints[3] = swab32(mdp0->set_uuid3);
+ }
+ ma = le32_to_cpu(mdp0->major_version);
+ mi = le32_to_cpu(mdp0->minor_version);
+ pa = le32_to_cpu(mdp0->patch_version);
+ size = le32_to_cpu(mdp0->size);
+
+ } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
+ uuid.ints[0] = mdp0->set_uuid0;
+ if (be32_to_cpu(mdp0->minor_version) >= 90) {
+ uuid.ints[1] = mdp0->set_uuid1;
+ uuid.ints[2] = mdp0->set_uuid2;
+ uuid.ints[3] = mdp0->set_uuid3;
+ }
+ ma = be32_to_cpu(mdp0->major_version);
+ mi = be32_to_cpu(mdp0->minor_version);
+ pa = be32_to_cpu(mdp0->patch_version);
+ size = be32_to_cpu(mdp0->size);
+ } else
+ return 1;
+
+ size <<= 10; /* convert KiB to bytes */
+
+ if (pr->size < 0 || (uint64_t) pr->size < size + MD_RESERVED_BYTES)
+ /* device is too small */
+ return 1;
+
+ if (off < 0 || (uint64_t) off < size)
+ /* no space before superblock */
+ return 1;
+
+ /*
+ * Check for collisions between RAID and partition table
+ *
+ * For example the superblock is at the end of the last partition, it's
+ * the same position as at the end of the disk...
+ */
+ if ((S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) &&
+ blkid_probe_is_covered_by_pt(pr,
+ off - size, /* min. start */
+ size + MD_RESERVED_BYTES)) { /* min. length */
+
+ /* ignore this superblock, it's within any partition and
+ * we are working with whole-disk now */
+ return 1;
+ }
+
+ if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0)
+ return -1;
+ if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic),
+ (unsigned char *) &mdp0->md_magic))
+ return -1;
+ return 0;
+}
+
+static int probe_raid1(blkid_probe pr, off_t off)
+{
+ struct mdp1_super_block *mdp1;
+
+ mdp1 = (struct mdp1_super_block *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct mdp1_super_block));
+ if (!mdp1)
+ return -1;
+ if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
+ return -1;
+ if (le32_to_cpu(mdp1->major_version) != 1U)
+ return -1;
+ if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9)
+ return -1;
+ if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
+ return -1;
+ if (blkid_probe_set_uuid_as(pr,
+ (unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0)
+ return -1;
+ if (blkid_probe_set_label(pr, mdp1->set_name,
+ sizeof(mdp1->set_name)) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic),
+ (unsigned char *) &mdp1->magic))
+ return -1;
+ return 0;
+}
+
+int probe_raid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ const char *ver = NULL;
+
+ if (pr->size > MD_RESERVED_BYTES) {
+ /* version 0 at the end of the device */
+ uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
+ - MD_RESERVED_BYTES;
+ if (probe_raid0(pr, sboff) == 0)
+ return 0;
+
+ /* version 1.0 at the end of the device */
+ sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
+ if (probe_raid1(pr, sboff) == 0)
+ ver = "1.0";
+ }
+
+ if (!ver) {
+ /* version 1.1 at the start of the device */
+ if (probe_raid1(pr, 0) == 0)
+ ver = "1.1";
+
+ /* version 1.2 at 4k offset from the start */
+ else if (probe_raid1(pr, 0x1000) == 0)
+ ver = "1.2";
+ }
+
+ if (ver) {
+ blkid_probe_set_version(pr, ver);
+ return 0;
+ }
+ return -1;
+}
+
+
+const struct blkid_idinfo linuxraid_idinfo = {
+ .name = "linux_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_raid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/lsi_raid.c b/libblkid/src/superblocks/lsi_raid.c
new file mode 100644
index 0000000..56721dd
--- /dev/null
+++ b/libblkid/src/superblocks/lsi_raid.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct lsi_metadata {
+ uint8_t sig[6];
+};
+
+
+#define LSI_SIGNATURE "$XIDE$"
+
+static int probe_lsiraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t off;
+ struct lsi_metadata *lsi;
+
+ if (pr->size < 0x10000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200) - 1) * 0x200;
+ lsi = (struct lsi_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct lsi_metadata));
+ if (!lsi)
+ return -1;
+
+ if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(lsi->sig),
+ (unsigned char *) lsi->sig))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo lsiraid_idinfo = {
+ .name = "lsi_mega_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_lsiraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/luks.c b/libblkid/src/superblocks/luks.c
new file mode 100644
index 0000000..f716e31
--- /dev/null
+++ b/libblkid/src/superblocks/luks.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+#define LUKS_CIPHERNAME_L 32
+#define LUKS_CIPHERMODE_L 32
+#define LUKS_HASHSPEC_L 32
+#define LUKS_DIGESTSIZE 20
+#define LUKS_SALTSIZE 32
+#define LUKS_MAGIC_L 6
+#define UUID_STRING_L 40
+
+struct luks_phdr {
+ uint8_t magic[LUKS_MAGIC_L];
+ uint16_t version;
+ uint8_t cipherName[LUKS_CIPHERNAME_L];
+ uint8_t cipherMode[LUKS_CIPHERMODE_L];
+ uint8_t hashSpec[LUKS_HASHSPEC_L];
+ uint32_t payloadOffset;
+ uint32_t keyBytes;
+ uint8_t mkDigest[LUKS_DIGESTSIZE];
+ uint8_t mkDigestSalt[LUKS_SALTSIZE];
+ uint32_t mkDigestIterations;
+ uint8_t uuid[UUID_STRING_L];
+} __attribute__((packed));
+
+static int probe_luks(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct luks_phdr *header;
+
+ header = blkid_probe_get_sb(pr, mag, struct luks_phdr);
+ if (header == NULL)
+ return -1;
+
+ blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid,
+ sizeof(header->uuid));
+ blkid_probe_sprintf_version(pr, "%u", be16_to_cpu(header->version));
+ return 0;
+}
+
+const struct blkid_idinfo luks_idinfo =
+{
+ .name = "crypto_LUKS",
+ .usage = BLKID_USAGE_CRYPTO,
+ .probefunc = probe_luks,
+ .magics =
+ {
+ { .magic = "LUKS\xba\xbe", .len = 6 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/lvm.c b/libblkid/src/superblocks/lvm.c
new file mode 100644
index 0000000..0afc773
--- /dev/null
+++ b/libblkid/src/superblocks/lvm.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2012 Milan Broz <mbroz@redhat.com>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+#define LVM1_ID_LEN 128
+#define LVM2_ID_LEN 32
+
+struct lvm2_pv_label_header {
+ /* label_header */
+ uint8_t id[8]; /* LABELONE */
+ uint64_t sector_xl; /* Sector number of this label */
+ uint32_t crc_xl; /* From next field to end of sector */
+ uint32_t offset_xl; /* Offset from start of struct to contents */
+ uint8_t type[8]; /* LVM2 001 */
+ /* pv_header */
+ uint8_t pv_uuid[LVM2_ID_LEN];
+} __attribute__ ((packed));
+
+struct lvm1_pv_label_header {
+ uint8_t id[2]; /* HM */
+ uint16_t version; /* version 1 or 2 */
+ uint32_t _notused[10]; /* lvm1 internals */
+ uint8_t pv_uuid[LVM1_ID_LEN];
+} __attribute__ ((packed));
+
+#define LVM2_LABEL_SIZE 512
+static unsigned int lvm2_calc_crc(const void *buf, unsigned int size)
+{
+ static const unsigned int crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ unsigned int i, crc = 0xf597a6cf;
+ const uint8_t *data = (const uint8_t *) buf;
+
+ for (i = 0; i < size; i++) {
+ crc ^= *data++;
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+ return crc;
+}
+
+/* Length of real UUID is always LVM2_ID_LEN */
+static void format_lvm_uuid(char *dst_uuid, char *src_uuid)
+{
+ unsigned int i, b;
+
+ for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) {
+ if (b & 0x4444440)
+ *dst_uuid++ = '-';
+ *dst_uuid++ = *src_uuid++;
+ }
+ *dst_uuid = '\0';
+}
+
+static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ int sector = mag->kboff << 1;
+ struct lvm2_pv_label_header *label;
+ char uuid[LVM2_ID_LEN + 7];
+ unsigned char *buf;
+
+ buf = blkid_probe_get_buffer(pr,
+ mag->kboff << 10,
+ 512 + sizeof(struct lvm2_pv_label_header));
+ if (!buf)
+ return -1;
+
+ /* buf is at 0k or 1k offset; find label inside */
+ if (memcmp(buf, "LABELONE", 8) == 0) {
+ label = (struct lvm2_pv_label_header *) buf;
+ } else if (memcmp(buf + 512, "LABELONE", 8) == 0) {
+ label = (struct lvm2_pv_label_header *)(buf + 512);
+ sector++;
+ } else {
+ return 1;
+ }
+
+ if (le64_to_cpu(label->sector_xl) != (unsigned) sector)
+ return 1;
+
+ if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE -
+ ((char *) &label->offset_xl - (char *) label)) !=
+ le32_to_cpu(label->crc_xl)) {
+ DBG(DEBUG_PROBE,
+ printf("LVM2: label checksum incorrect at sector %d\n",
+ sector));
+ return 1;
+ }
+
+ format_lvm_uuid(uuid, (char *) label->pv_uuid);
+ blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
+ "%s", uuid);
+
+ /* the mag->magic is the same string as label->type,
+ * but zero terminated */
+ blkid_probe_set_version(pr, mag->magic);
+
+ /* LVM (pvcreate) wipes begin of the device -- let's remember this
+ * to resolve conflicts bettween LVM and partition tables, ...
+ */
+ blkid_probe_set_wiper(pr, 0, 8 * 1024);
+
+ return 0;
+}
+
+static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct lvm1_pv_label_header *label;
+ char uuid[LVM2_ID_LEN + 7];
+ unsigned int version;
+
+ label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header);
+ if (!label)
+ return -1;
+
+ version = le16_to_cpu(label->version);
+ if (version != 1 && version != 2)
+ return 1;
+
+ format_lvm_uuid(uuid, (char *) label->pv_uuid);
+ blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
+ "%s", uuid);
+
+ return 0;
+}
+
+struct verity_sb {
+ uint8_t signature[8]; /* "verity\0\0" */
+ uint32_t version; /* superblock version */
+ uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */
+ uint8_t uuid[16]; /* UUID of hash device */
+ uint8_t algorithm[32];/* hash algorithm name */
+ uint32_t data_block_size; /* data block in bytes */
+ uint32_t hash_block_size; /* hash block in bytes */
+ uint64_t data_blocks; /* number of data blocks */
+ uint16_t salt_size; /* salt size */
+ uint8_t _pad1[6];
+ uint8_t salt[256]; /* salt */
+ uint8_t _pad2[168];
+} __attribute__((packed));
+
+static int probe_verity(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct verity_sb *sb;
+ unsigned int version;
+
+ sb = blkid_probe_get_sb(pr, mag, struct verity_sb);
+ if (sb == NULL)
+ return -1;
+
+ version = le32_to_cpu(sb->version);
+ if (version != 1)
+ return 1;
+
+ blkid_probe_set_uuid(pr, sb->uuid);
+ blkid_probe_sprintf_version(pr, "%u", version);
+ return 0;
+}
+
+/* NOTE: the original libblkid uses "lvm2pv" as a name */
+const struct blkid_idinfo lvm2_idinfo =
+{
+ .name = "LVM2_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_lvm2,
+ .magics =
+ {
+ { .magic = "LVM2 001", .len = 8, .sboff = 0x218 },
+ { .magic = "LVM2 001", .len = 8, .sboff = 0x018 },
+ { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 },
+ { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo lvm1_idinfo =
+{
+ .name = "LVM1_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_lvm1,
+ .magics =
+ {
+ { .magic = "HM", .len = 2 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo snapcow_idinfo =
+{
+ .name = "DM_snapshot_cow",
+ .usage = BLKID_USAGE_OTHER,
+ .magics =
+ {
+ { .magic = "SnAp", .len = 4 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo verity_hash_idinfo =
+{
+ .name = "DM_verity_hash",
+ .usage = BLKID_USAGE_CRYPTO,
+ .probefunc = probe_verity,
+ .magics =
+ {
+ { .magic = "verity\0\0", .len = 8 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/minix.c b/libblkid/src/superblocks/minix.c
new file mode 100644
index 0000000..54e7139
--- /dev/null
+++ b/libblkid/src/superblocks/minix.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <string.h>
+#include "superblocks.h"
+#include "minix.h"
+
+static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ unsigned char *ext;
+ int version;
+
+ /* for more details see magic strings below */
+ switch(mag->magic[1]) {
+ case '\023':
+ version = 1;
+ break;
+ case '\044':
+ version = 2;
+ break;
+ case '\115':
+ version = 3;
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ if (version <= 2) {
+ struct minix_super_block *sb;
+ uint32_t zones;
+
+ sb = blkid_probe_get_sb(pr, mag, struct minix_super_block);
+ if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+ return -1;
+
+ zones = version == 2 ? sb->s_zones : sb->s_nzones;
+
+ /* sanity checks to be sure that the FS is really minix */
+ if (sb->s_imap_blocks * MINIX_BLOCK_SIZE * 8 < sb->s_ninodes + 1)
+ return -1;
+ if (sb->s_zmap_blocks * MINIX_BLOCK_SIZE * 8 < zones - sb->s_firstdatazone + 1)
+ return -1;
+
+ } else if (version == 3) {
+ struct minix3_super_block *sb;
+
+ sb = blkid_probe_get_sb(pr, mag, struct minix3_super_block);
+ if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+ return -1;
+
+ }
+
+ /* unfortunately, some parts of ext3 is sometimes possible to
+ * interpreted as minix superblock. So check for extN magic
+ * string. (For extN magic string and offsets see ext.c.)
+ */
+ ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2);
+ if (ext && memcmp(ext, "\123\357", 2) == 0)
+ return -1;
+
+ blkid_probe_sprintf_version(pr, "%d", version);
+ return 0;
+}
+
+const struct blkid_idinfo minix_idinfo =
+{
+ .name = "minix",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_minix,
+ .magics =
+ {
+ /* version 1 */
+ { .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 },
+ { .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+ /* version 2 */
+ { .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 },
+ { .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+ /* version 3 */
+ { .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/netware.c b/libblkid/src/superblocks/netware.c
new file mode 100644
index 0000000..7ef2162
--- /dev/null
+++ b/libblkid/src/superblocks/netware.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct netware_super_block {
+ uint8_t SBH_Signature[4];
+ uint16_t SBH_VersionMajor;
+ uint16_t SBH_VersionMinor;
+ uint16_t SBH_VersionMediaMajor;
+ uint16_t SBH_VersionMediaMinor;
+ uint32_t SBH_ItemsMoved;
+ uint8_t SBH_InternalID[16];
+ uint32_t SBH_PackedSize;
+ uint32_t SBH_Checksum;
+ uint32_t supersyncid;
+ int64_t superlocation[4];
+ uint32_t physSizeUsed;
+ uint32_t sizeUsed;
+ uint32_t superTimeStamp;
+ uint32_t reserved0[1];
+ int64_t SBH_LoggedPoolDataBlk;
+ int64_t SBH_PoolDataBlk;
+ uint8_t SBH_OldInternalID[16];
+ uint32_t SBH_PoolToLVStartUTC;
+ uint32_t SBH_PoolToLVEndUTC;
+ uint16_t SBH_VersionMediaMajorCreate;
+ uint16_t SBH_VersionMediaMinorCreate;
+ uint32_t SBH_BlocksMoved;
+ uint32_t SBH_TempBTSpBlk;
+ uint32_t SBH_TempFTSpBlk;
+ uint32_t SBH_TempFTSpBlk1;
+ uint32_t SBH_TempFTSpBlk2;
+ uint32_t nssMagicNumber;
+ uint32_t poolClassID;
+ uint32_t poolID;
+ uint32_t createTime;
+ int64_t SBH_LoggedVolumeDataBlk;
+ int64_t SBH_VolumeDataBlk;
+ int64_t SBH_SystemBeastBlkNum;
+ uint64_t totalblocks;
+ uint16_t SBH_Name[64];
+ uint8_t SBH_VolumeID[16];
+ uint8_t SBH_PoolID[16];
+ uint8_t SBH_PoolInternalID[16];
+ uint64_t SBH_Lsn;
+ uint32_t SBH_SS_Enabled;
+ uint32_t SBH_SS_CreateTime;
+ uint8_t SBH_SS_OriginalPoolID[16];
+ uint8_t SBH_SS_OriginalVolumeID[16];
+ uint8_t SBH_SS_Guid[16];
+ uint16_t SBH_SS_OriginalName[64];
+ uint32_t reserved2[64-(2+46)];
+} __attribute__((__packed__));
+
+static int probe_netware(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct netware_super_block *nw;
+
+ nw = blkid_probe_get_sb(pr, mag, struct netware_super_block);
+ if (!nw)
+ return -1;
+
+ blkid_probe_set_uuid(pr, nw->SBH_PoolID);
+
+ blkid_probe_sprintf_version(pr, "%u.%02u",
+ le16_to_cpu(nw->SBH_VersionMediaMajor),
+ le16_to_cpu(nw->SBH_VersionMediaMinor));
+
+ return 0;
+}
+
+const struct blkid_idinfo netware_idinfo =
+{
+ .name = "nss",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_netware,
+ .magics =
+ {
+ { .magic = "SPB5", .len = 4, .kboff = 4 },
+ { NULL }
+ }
+};
+
+
diff --git a/libblkid/src/superblocks/nilfs.c b/libblkid/src/superblocks/nilfs.c
new file mode 100644
index 0000000..1f8f3a6
--- /dev/null
+++ b/libblkid/src/superblocks/nilfs.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 by Jiro SEKIBA <jir@unicus.jp>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License
+ */
+#include <stddef.h>
+#include <string.h>
+
+#include "superblocks.h"
+#include "crc32.h"
+
+struct nilfs_super_block {
+ uint32_t s_rev_level;
+ uint16_t s_minor_rev_level;
+ uint16_t s_magic;
+
+ uint16_t s_bytes;
+
+ uint16_t s_flags;
+ uint32_t s_crc_seed;
+ uint32_t s_sum;
+
+ uint32_t s_log_block_size;
+
+ uint64_t s_nsegments;
+ uint64_t s_dev_size;
+ uint64_t s_first_data_block;
+ uint32_t s_blocks_per_segment;
+ uint32_t s_r_segments_percentage;
+
+ uint64_t s_last_cno;
+ uint64_t s_last_pseg;
+ uint64_t s_last_seq;
+ uint64_t s_free_blocks_count;
+
+ uint64_t s_ctime;
+
+ uint64_t s_mtime;
+ uint64_t s_wtime;
+ uint16_t s_mnt_count;
+ uint16_t s_max_mnt_count;
+ uint16_t s_state;
+ uint16_t s_errors;
+ uint64_t s_lastcheck;
+
+ uint32_t s_checkinterval;
+ uint32_t s_creator_os;
+ uint16_t s_def_resuid;
+ uint16_t s_def_resgid;
+ uint32_t s_first_ino;
+
+ uint16_t s_inode_size;
+ uint16_t s_dat_entry_size;
+ uint16_t s_checkpoint_size;
+ uint16_t s_segment_usage_size;
+
+ uint8_t s_uuid[16];
+ char s_volume_name[80];
+
+ uint32_t s_c_interval;
+ uint32_t s_c_block_max;
+ uint32_t s_reserved[192];
+};
+
+/* nilfs2 magic string */
+#define NILFS_SB_MAGIC "\x34\x34"
+/* nilfs2 super block offset */
+#define NILFS_SB_OFF 0x400
+/* nilfs2 super block offset in kB */
+#define NILFS_SB_KBOFF (NILFS_SB_OFF >> 10)
+/* nilfs2 magic string offset within super block */
+#define NILFS_MAG_OFF 6
+
+static int probe_nilfs2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct nilfs_super_block *sb;
+ static unsigned char sum[4];
+ const int sumoff = offsetof(struct nilfs_super_block, s_sum);
+ size_t bytes;
+ uint32_t crc;
+
+ sb = blkid_probe_get_sb(pr, mag, struct nilfs_super_block);
+ if (!sb)
+ return -1;
+
+ bytes = le16_to_cpu(sb->s_bytes);
+ crc = crc32(le32_to_cpu(sb->s_crc_seed), (unsigned char *)sb, sumoff);
+ crc = crc32(crc, sum, 4);
+ crc = crc32(crc, (unsigned char *)sb + sumoff + 4, bytes - sumoff - 4);
+
+ if (crc != le32_to_cpu(sb->s_sum))
+ return -1;
+
+ if (strlen(sb->s_volume_name))
+ blkid_probe_set_label(pr, (unsigned char *) sb->s_volume_name,
+ sizeof(sb->s_volume_name));
+
+ blkid_probe_set_uuid(pr, sb->s_uuid);
+ blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(sb->s_rev_level));
+
+ return 0;
+}
+
+const struct blkid_idinfo nilfs2_idinfo =
+{
+ .name = "nilfs2",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_nilfs2,
+ .magics =
+ {
+ {
+ .magic = NILFS_SB_MAGIC,
+ .len = 2,
+ .kboff = NILFS_SB_KBOFF,
+ .sboff = NILFS_MAG_OFF
+ },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/ntfs.c b/libblkid/src/superblocks/ntfs.c
new file mode 100644
index 0000000..41c6b9c
--- /dev/null
+++ b/libblkid/src/superblocks/ntfs.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 "superblocks.h"
+
+struct ntfs_bios_parameters {
+ uint16_t sector_size; /* Size of a sector in bytes. */
+ uint8_t sectors_per_cluster; /* Size of a cluster in sectors. */
+ uint16_t reserved_sectors; /* zero */
+ uint8_t fats; /* zero */
+ uint16_t root_entries; /* zero */
+ uint16_t sectors; /* zero */
+ uint8_t media_type; /* 0xf8 = hard disk */
+ uint16_t sectors_per_fat; /* zero */
+ uint16_t sectors_per_track; /* irrelevant */
+ uint16_t heads; /* irrelevant */
+ uint32_t hidden_sectors; /* zero */
+ uint32_t large_sectors; /* zero */
+} __attribute__ ((__packed__));
+
+struct ntfs_super_block {
+ uint8_t jump[3];
+ uint8_t oem_id[8]; /* magic string */
+
+ struct ntfs_bios_parameters bpb;
+
+ uint16_t unused[2];
+ uint64_t number_of_sectors;
+ uint64_t mft_cluster_location;
+ uint64_t mft_mirror_cluster_location;
+ int8_t clusters_per_mft_record;
+ uint8_t reserved1[3];
+ int8_t cluster_per_index_record;
+ uint8_t reserved2[3];
+ uint64_t volume_serial;
+ uint32_t checksum;
+} __attribute__((packed));
+
+struct master_file_table_record {
+ uint32_t magic;
+ uint16_t usa_ofs;
+ uint16_t usa_count;
+ uint64_t lsn;
+ uint16_t sequence_number;
+ uint16_t link_count;
+ uint16_t attrs_offset;
+ uint16_t flags;
+ uint32_t bytes_in_use;
+ uint32_t bytes_allocated;
+} __attribute__((__packed__));
+
+struct file_attribute {
+ uint32_t type;
+ uint32_t len;
+ uint8_t non_resident;
+ uint8_t name_len;
+ uint16_t name_offset;
+ uint16_t flags;
+ uint16_t instance;
+ uint32_t value_len;
+ uint16_t value_offset;
+} __attribute__((__packed__));
+
+#define MFT_RECORD_VOLUME 3
+#define NTFS_MAX_CLUSTER_SIZE (64 * 1024)
+
+enum {
+ MFT_RECORD_ATTR_VOLUME_NAME = cpu_to_le32(0x60),
+ MFT_RECORD_ATTR_END = cpu_to_le32(0xffffffff)
+};
+
+static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct ntfs_super_block *ns;
+ struct master_file_table_record *mft;
+
+ uint32_t sectors_per_cluster, mft_record_size, attr_off;
+ uint16_t sector_size;
+ uint64_t nr_clusters, off;
+ unsigned char *buf_mft;
+
+ ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
+ if (!ns)
+ return -1;
+
+ /*
+ * Check bios parameters block
+ */
+ sector_size = le16_to_cpu(ns->bpb.sector_size);
+ sectors_per_cluster = ns->bpb.sectors_per_cluster;
+
+ if (sector_size < 256 || sector_size > 4096)
+ return 1;
+
+ switch (sectors_per_cluster) {
+ case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
+ break;
+ default:
+ return 1;
+ }
+
+ if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) *
+ ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE)
+ return 1;
+
+ /* Unused fields must be zero */
+ if (le16_to_cpu(ns->bpb.reserved_sectors)
+ || le16_to_cpu(ns->bpb.root_entries)
+ || le16_to_cpu(ns->bpb.sectors)
+ || le16_to_cpu(ns->bpb.sectors_per_fat)
+ || le32_to_cpu(ns->bpb.large_sectors)
+ || ns->bpb.fats)
+ return 1;
+
+ if ((uint8_t) ns->clusters_per_mft_record < 0xe1
+ || (uint8_t) ns->clusters_per_mft_record > 0xf7) {
+
+ switch (ns->clusters_per_mft_record) {
+ case 1: case 2: case 4: case 8: case 16: case 32: case 64:
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ if (ns->clusters_per_mft_record > 0)
+ mft_record_size = ns->clusters_per_mft_record *
+ sectors_per_cluster * sector_size;
+ else
+ mft_record_size = 1 << (0 - ns->clusters_per_mft_record);
+
+ nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
+
+ if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
+ (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
+ return 1;
+
+
+ off = le64_to_cpu(ns->mft_cluster_location) * sector_size *
+ sectors_per_cluster;
+
+ DBG(DEBUG_LOWPROBE, printf("NTFS: sector_size=%d, mft_record_size=%d, "
+ "sectors_per_cluster=%d, nr_clusters=%ju "
+ "cluster_offset=%jd\n",
+ (int) sector_size, mft_record_size,
+ sectors_per_cluster, nr_clusters,
+ off));
+
+ buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
+ if (!buf_mft)
+ return 1;
+
+ if (memcmp(buf_mft, "FILE", 4))
+ return 1;
+
+ off += MFT_RECORD_VOLUME * mft_record_size;
+
+ buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
+ if (!buf_mft)
+ return 1;
+
+ if (memcmp(buf_mft, "FILE", 4))
+ return 1;
+
+ mft = (struct master_file_table_record *) buf_mft;
+ attr_off = le16_to_cpu(mft->attrs_offset);
+
+ while (attr_off < mft_record_size &&
+ attr_off <= le32_to_cpu(mft->bytes_allocated)) {
+
+ uint32_t attr_len;
+ struct file_attribute *attr;
+
+ attr = (struct file_attribute *) (buf_mft + attr_off);
+ attr_len = le32_to_cpu(attr->len);
+ if (!attr_len)
+ break;
+
+ if (attr->type == MFT_RECORD_ATTR_END)
+ break;
+ if (attr->type == MFT_RECORD_ATTR_VOLUME_NAME) {
+ unsigned int val_off = le16_to_cpu(attr->value_offset);
+ unsigned int val_len = le32_to_cpu(attr->value_len);
+ unsigned char *val = ((uint8_t *) attr) + val_off;
+
+ blkid_probe_set_utf8label(pr, val, val_len, BLKID_ENC_UTF16LE);
+ break;
+ }
+
+ if (UINT_MAX - attr_len < attr_off)
+ break;
+ attr_off += attr_len;
+ }
+
+ blkid_probe_sprintf_uuid(pr,
+ (unsigned char *) &ns->volume_serial,
+ sizeof(ns->volume_serial),
+ "%016" PRIX64, le64_to_cpu(ns->volume_serial));
+ return 0;
+}
+
+
+const struct blkid_idinfo ntfs_idinfo =
+{
+ .name = "ntfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ntfs,
+ .magics =
+ {
+ { .magic = "NTFS ", .len = 8, .sboff = 3 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/nvidia_raid.c b/libblkid/src/superblocks/nvidia_raid.c
new file mode 100644
index 0000000..dd86cdc
--- /dev/null
+++ b/libblkid/src/superblocks/nvidia_raid.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct nv_metadata {
+ uint8_t vendor[8];
+ uint32_t size;
+ uint32_t chksum;
+ uint16_t version;
+} __attribute__((packed));
+
+#define NVIDIA_SIGNATURE "NVIDIA"
+
+static int probe_nvraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t off;
+ struct nv_metadata *nv;
+
+ if (pr->size < 0x10000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200) - 2) * 0x200;
+ nv = (struct nv_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct nv_metadata));
+ if (!nv)
+ return -1;
+
+ if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
+ return -1;
+ if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off, sizeof(nv->vendor),
+ (unsigned char *) nv->vendor))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo nvraid_idinfo = {
+ .name = "nvidia_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_nvraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/ocfs.c b/libblkid/src/superblocks/ocfs.c
new file mode 100644
index 0000000..82170ac
--- /dev/null
+++ b/libblkid/src/superblocks/ocfs.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct ocfs_volume_header {
+ unsigned char minor_version[4];
+ unsigned char major_version[4];
+ unsigned char signature[128];
+ char mount[128];
+ unsigned char mount_len[2];
+} __attribute__((packed));
+
+struct ocfs_volume_label {
+ unsigned char disk_lock[48];
+ char label[64];
+ unsigned char label_len[2];
+ unsigned char vol_id[16];
+ unsigned char vol_id_len[2];
+} __attribute__((packed));
+
+#define ocfsmajor(o) ( (uint32_t) o.major_version[0] \
+ + (((uint32_t) o.major_version[1]) << 8) \
+ + (((uint32_t) o.major_version[2]) << 16) \
+ + (((uint32_t) o.major_version[3]) << 24))
+
+#define ocfsminor(o) ( (uint32_t) o.minor_version[0] \
+ + (((uint32_t) o.minor_version[1]) << 8) \
+ + (((uint32_t) o.minor_version[2]) << 16) \
+ + (((uint32_t) o.minor_version[3]) << 24))
+
+#define ocfslabellen(o) ((uint32_t)o.label_len[0] + (((uint32_t) o.label_len[1]) << 8))
+#define ocfsmountlen(o) ((uint32_t)o.mount_len[0] + (((uint32_t) o.mount_len[1]) << 8))
+
+struct ocfs2_super_block {
+ uint8_t i_signature[8];
+ uint32_t i_generation;
+ int16_t i_suballoc_slot;
+ uint16_t i_suballoc_bit;
+ uint32_t i_reserved0;
+ uint32_t i_clusters;
+ uint32_t i_uid;
+ uint32_t i_gid;
+ uint64_t i_size;
+ uint16_t i_mode;
+ uint16_t i_links_count;
+ uint32_t i_flags;
+ uint64_t i_atime;
+ uint64_t i_ctime;
+ uint64_t i_mtime;
+ uint64_t i_dtime;
+ uint64_t i_blkno;
+ uint64_t i_last_eb_blk;
+ uint32_t i_fs_generation;
+ uint32_t i_atime_nsec;
+ uint32_t i_ctime_nsec;
+ uint32_t i_mtime_nsec;
+ uint64_t i_reserved1[9];
+ uint64_t i_pad1;
+ uint16_t s_major_rev_level;
+ uint16_t s_minor_rev_level;
+ uint16_t s_mnt_count;
+ int16_t s_max_mnt_count;
+ uint16_t s_state;
+ uint16_t s_errors;
+ uint32_t s_checkinterval;
+ uint64_t s_lastcheck;
+ uint32_t s_creator_os;
+ uint32_t s_feature_compat;
+ uint32_t s_feature_incompat;
+ uint32_t s_feature_ro_compat;
+ uint64_t s_root_blkno;
+ uint64_t s_system_dir_blkno;
+ uint32_t s_blocksize_bits;
+ uint32_t s_clustersize_bits;
+ uint16_t s_max_slots;
+ uint16_t s_reserved1;
+ uint32_t s_reserved2;
+ uint64_t s_first_cluster_group;
+ uint8_t s_label[64];
+ uint8_t s_uuid[16];
+} __attribute__((packed));
+
+struct oracle_asm_disk_label {
+ char dummy[32];
+ char dl_tag[8];
+ char dl_id[24];
+} __attribute__((packed));
+
+static int probe_ocfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ unsigned char *buf;
+ struct ocfs_volume_header ovh;
+ struct ocfs_volume_label ovl;
+ uint32_t maj, min;
+
+ /* header */
+ buf = blkid_probe_get_buffer(pr, mag->kboff << 10,
+ sizeof(struct ocfs_volume_header));
+ if (!buf)
+ return -1;
+ memcpy(&ovh, buf, sizeof(ovh));
+
+ /* label */
+ buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512,
+ sizeof(struct ocfs_volume_label));
+ if (!buf)
+ return -1;
+ memcpy(&ovl, buf, sizeof(ovl));
+
+ maj = ocfsmajor(ovh);
+ min = ocfsminor(ovh);
+
+ if (maj == 1)
+ blkid_probe_set_value(pr, "SEC_TYPE",
+ (unsigned char *) "ocfs1", sizeof("ocfs1"));
+ else if (maj >= 9)
+ blkid_probe_set_value(pr, "SEC_TYPE",
+ (unsigned char *) "ntocfs", sizeof("ntocfs"));
+
+ blkid_probe_set_label(pr, (unsigned char *) ovl.label,
+ ocfslabellen(ovl));
+ blkid_probe_set_value(pr, "MOUNT", (unsigned char *) ovh.mount,
+ ocfsmountlen(ovh));
+ blkid_probe_set_uuid(pr, ovl.vol_id);
+ blkid_probe_sprintf_version(pr, "%u.%u", maj, min);
+ return 0;
+}
+
+static int probe_ocfs2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct ocfs2_super_block *osb;
+
+ osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block);
+ if (!osb)
+ return -1;
+
+ blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label));
+ blkid_probe_set_uuid(pr, osb->s_uuid);
+
+ blkid_probe_sprintf_version(pr, "%u.%u",
+ le16_to_cpu(osb->s_major_rev_level),
+ le16_to_cpu(osb->s_minor_rev_level));
+
+ return 0;
+}
+
+static int probe_oracleasm(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct oracle_asm_disk_label *dl;
+
+ dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label);
+ if (!dl)
+ return -1;
+
+ blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id));
+ return 0;
+}
+
+
+const struct blkid_idinfo ocfs_idinfo =
+{
+ .name = "ocfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ocfs,
+ .minsz = 14000 * 1024,
+ .magics =
+ {
+ { .magic = "OracleCFS", .len = 9, .kboff = 8 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo ocfs2_idinfo =
+{
+ .name = "ocfs2",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ocfs2,
+ .minsz = 14000 * 1024,
+ .magics =
+ {
+ { .magic = "OCFSV2", .len = 6, .kboff = 1 },
+ { .magic = "OCFSV2", .len = 6, .kboff = 2 },
+ { .magic = "OCFSV2", .len = 6, .kboff = 4 },
+ { .magic = "OCFSV2", .len = 6, .kboff = 8 },
+ { NULL }
+ }
+};
+
+/* Oracle ASM (Automatic Storage Management) */
+const struct blkid_idinfo oracleasm_idinfo =
+{
+ .name = "oracleasm",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_oracleasm,
+ .magics =
+ {
+ { .magic = "ORCLDISK", .len = 8, .sboff = 32 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/promise_raid.c b/libblkid/src/superblocks/promise_raid.c
new file mode 100644
index 0000000..221146d
--- /dev/null
+++ b/libblkid/src/superblocks/promise_raid.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct promise_metadata {
+ uint8_t sig[24];
+};
+
+#define PDC_CONFIG_OFF 0x1200
+#define PDC_SIGNATURE "Promise Technology, Inc."
+
+static int probe_pdcraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ unsigned int i;
+ static unsigned int sectors[] = {
+ 63, 255, 256, 16, 399, 0
+ };
+
+ if (pr->size < 0x40000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ for (i = 0; sectors[i] != 0; i++) {
+ uint64_t off;
+ struct promise_metadata *pdc;
+
+ off = ((pr->size / 0x200) - sectors[i]) * 0x200;
+ pdc = (struct promise_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct promise_metadata));
+ if (!pdc)
+ return -1;
+
+ if (memcmp(pdc->sig, PDC_SIGNATURE,
+ sizeof(PDC_SIGNATURE) - 1) == 0) {
+
+ if (blkid_probe_set_magic(pr, off, sizeof(pdc->sig),
+ (unsigned char *) pdc->sig))
+ return -1;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+const struct blkid_idinfo pdcraid_idinfo = {
+ .name = "promise_fasttrack_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_pdcraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/reiserfs.c b/libblkid/src/superblocks/reiserfs.c
new file mode 100644
index 0000000..152571f
--- /dev/null
+++ b/libblkid/src/superblocks/reiserfs.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+struct reiserfs_super_block {
+ uint32_t rs_blocks_count;
+ uint32_t rs_free_blocks;
+ uint32_t rs_root_block;
+ uint32_t rs_journal_block;
+ uint32_t rs_journal_dev;
+ uint32_t rs_orig_journal_size;
+ uint32_t rs_dummy2[5];
+ uint16_t rs_blocksize;
+ uint16_t rs_dummy3[3];
+ unsigned char rs_magic[12];
+ uint32_t rs_dummy4[5];
+ unsigned char rs_uuid[16];
+ char rs_label[16];
+} __attribute__((packed));
+
+struct reiser4_super_block {
+ unsigned char rs4_magic[16];
+ uint16_t rs4_dummy[2];
+ unsigned char rs4_uuid[16];
+ unsigned char rs4_label[16];
+ uint64_t rs4_dummy2;
+} __attribute__((packed));
+
+static int probe_reiser(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct reiserfs_super_block *rs;
+ unsigned int blocksize;
+
+ rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block);
+ if (!rs)
+ return -1;
+
+ blocksize = le16_to_cpu(rs->rs_blocksize);
+
+ /* The blocksize must be at least 512B */
+ if ((blocksize >> 9) == 0)
+ return -BLKID_ERR_PARAM;
+
+ /* If the superblock is inside the journal, we have the wrong one */
+ if (mag->kboff / (blocksize >> 9) > le32_to_cpu(rs->rs_journal_block) / 2)
+ return -BLKID_ERR_BIG;
+
+ /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
+ if (mag->magic[6] == '2' || mag->magic[6] == '3') {
+ if (*rs->rs_label)
+ blkid_probe_set_label(pr,
+ (unsigned char *) rs->rs_label,
+ sizeof(rs->rs_label));
+ blkid_probe_set_uuid(pr, rs->rs_uuid);
+ }
+
+ if (mag->magic[6] == '3')
+ blkid_probe_set_version(pr, "JR");
+ else if (mag->magic[6] == '2')
+ blkid_probe_set_version(pr, "3.6");
+ else
+ blkid_probe_set_version(pr, "3.5");
+
+ return 0;
+}
+
+static int probe_reiser4(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct reiser4_super_block *rs4;
+
+ rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block);
+ if (!rs4)
+ return -1;
+
+ if (*rs4->rs4_label)
+ blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label));
+ blkid_probe_set_uuid(pr, rs4->rs4_uuid);
+ blkid_probe_set_version(pr, "4");
+
+ return 0;
+}
+
+
+const struct blkid_idinfo reiser_idinfo =
+{
+ .name = "reiserfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_reiser,
+ .minsz = 128 * 1024,
+ .magics =
+ {
+ { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 0x34 },
+ { .magic = "ReIsEr2Fs", .len = 9, .kboff = 64, .sboff = 0x34 },
+ { .magic = "ReIsEr3Fs", .len = 9, .kboff = 64, .sboff = 0x34 },
+ { .magic = "ReIsErFs", .len = 8, .kboff = 64, .sboff = 0x34 },
+ { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 20 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo reiser4_idinfo =
+{
+ .name = "reiser4",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_reiser4,
+ .minsz = 128 * 1024,
+ .magics =
+ {
+ { .magic = "ReIsEr4", .len = 7, .kboff = 64 },
+ { NULL }
+ }
+};
+
+
+
+
diff --git a/libblkid/src/superblocks/romfs.c b/libblkid/src/superblocks/romfs.c
new file mode 100644
index 0000000..91ef996
--- /dev/null
+++ b/libblkid/src/superblocks/romfs.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct romfs_super_block {
+ unsigned char ros_magic[8];
+ uint32_t ros_dummy1[2];
+ unsigned char ros_volume[16];
+} __attribute__((packed));
+
+static int probe_romfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct romfs_super_block *ros;
+
+ ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block);
+ if (!ros)
+ return -1;
+
+ if (strlen((char *) ros->ros_volume))
+ blkid_probe_set_label(pr, ros->ros_volume,
+ sizeof(ros->ros_volume));
+ return 0;
+}
+
+const struct blkid_idinfo romfs_idinfo =
+{
+ .name = "romfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_romfs,
+ .magics =
+ {
+ { .magic = "-rom1fs-", .len = 8 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/silicon_raid.c b/libblkid/src/superblocks/silicon_raid.c
new file mode 100644
index 0000000..fef5801
--- /dev/null
+++ b/libblkid/src/superblocks/silicon_raid.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+struct silicon_metadata {
+ uint8_t unknown0[0x2E];
+ uint8_t ascii_version[0x36 - 0x2E];
+ uint8_t diskname[0x56 - 0x36];
+ uint8_t unknown1[0x60 - 0x56];
+ uint32_t magic;
+ uint32_t unknown1a[0x6C - 0x64];
+ uint32_t array_sectors_low;
+ uint32_t array_sectors_high;
+ uint8_t unknown2[0x78 - 0x74];
+ uint32_t thisdisk_sectors;
+ uint8_t unknown3[0x100 - 0x7C];
+ uint8_t unknown4[0x104 - 0x100];
+ uint16_t product_id;
+ uint16_t vendor_id;
+ uint16_t minor_ver;
+ uint16_t major_ver;
+} __attribute__((packed));
+
+#define SILICON_MAGIC 0x2F000000
+
+
+static int probe_silraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t off;
+ struct silicon_metadata *sil;
+
+ if (pr->size < 0x10000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200) - 1) * 0x200;
+
+ sil = (struct silicon_metadata *)
+ blkid_probe_get_buffer(pr, off,
+ sizeof(struct silicon_metadata));
+ if (!sil)
+ return -1;
+
+ if (le32_to_cpu(sil->magic) != SILICON_MAGIC)
+ return -1;
+
+ if (blkid_probe_sprintf_version(pr, "%u.%u",
+ le16_to_cpu(sil->major_ver),
+ le16_to_cpu(sil->minor_ver)) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr,
+ off + offsetof(struct silicon_metadata, magic),
+ sizeof(sil->magic),
+ (unsigned char *) &sil->magic))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo silraid_idinfo = {
+ .name = "silicon_medley_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_silraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/squashfs.c b/libblkid/src/superblocks/squashfs.c
new file mode 100644
index 0000000..45f1029
--- /dev/null
+++ b/libblkid/src/superblocks/squashfs.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdint.h>
+
+#include "bitops.h" /* swab16() */
+#include "superblocks.h"
+
+struct sqsh_super_block {
+ uint32_t s_magic;
+ uint32_t inodes;
+ uint32_t bytes_used_2;
+ uint32_t uid_start_2;
+ uint32_t guid_start_2;
+ uint32_t inode_table_start_2;
+ uint32_t directory_table_start_2;
+ uint16_t s_major;
+ uint16_t s_minor;
+} __attribute__((packed));
+
+static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct sqsh_super_block *sq;
+
+ sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
+ if (!sq)
+ return -1;
+
+ if (strcmp(mag->magic, "sqsh") == 0 ||
+ strcmp(mag->magic, "qshs") == 0)
+ blkid_probe_sprintf_version(pr, "%u.%u",
+ sq->s_major,
+ sq->s_minor);
+ else
+ blkid_probe_sprintf_version(pr, "%u.%u",
+ swab16(sq->s_major),
+ swab16(sq->s_minor));
+ return 0;
+}
+
+const struct blkid_idinfo squashfs_idinfo =
+{
+ .name = "squashfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_squashfs,
+ .magics =
+ {
+ { .magic = "sqsh", .len = 4 },
+ { .magic = "hsqs", .len = 4 }, /* swap */
+
+ /* LZMA version */
+ { .magic = "qshs", .len = 4 },
+ { .magic = "shsq", .len = 4 }, /* swap */
+ { NULL }
+ }
+};
+
+
diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c
new file mode 100644
index 0000000..879a40f
--- /dev/null
+++ b/libblkid/src/superblocks/superblocks.c
@@ -0,0 +1,768 @@
+/*
+ * superblocks.c - reads information from filesystem and raid superblocks
+ *
+ * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "superblocks.h"
+
+/**
+ * SECTION:superblocks
+ * @title: Superblocks probing
+ * @short_description: filesystems and raids superblocks probing.
+ *
+ * The library API has been originally designed for superblocks probing only.
+ * This is reason why some *deprecated* superblock specific functions don't use
+ * '_superblocks_' namespace in the function name. Please, don't use these
+ * functions in new code.
+ *
+ * The 'superblocks' probers support NAME=value (tags) interface only. The
+ * superblocks probing is enabled by default (and controlled by
+ * blkid_probe_enable_superblocks()).
+ *
+ * Currently supported tags:
+ *
+ * @TYPE: filesystem type
+ *
+ * @SEC_TYPE: secondary filesystem type
+ *
+ * @LABEL: filesystem label
+ *
+ * @LABEL_RAW: raw label from FS superblock
+ *
+ * @UUID: filesystem UUID (lower case)
+ *
+ * @UUID_SUB: subvolume uuid (e.g. btrfs)
+ *
+ * @UUID_RAW: raw UUID from FS superblock
+ *
+ * @EXT_JOURNAL: external journal UUID
+ *
+ * @USAGE: usage string: "raid", "filesystem", ...
+ *
+ * @VERSION: filesystem version
+ *
+ * @MOUNT: cluster mount name (?) -- ocfs only
+ *
+ * @SBMAGIC: super block magic string
+ *
+ * @SBMAGIC_OFFSET: offset of SBMAGIC
+ *
+ * @FSSIZE: size of filessystem [not-implemented yet]
+ */
+
+static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn);
+static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn);
+
+static int blkid_probe_set_usage(blkid_probe pr, int usage);
+
+
+/*
+ * Superblocks chains probing functions
+ */
+static const struct blkid_idinfo *idinfos[] =
+{
+ /* RAIDs */
+ &linuxraid_idinfo,
+ &ddfraid_idinfo,
+ &iswraid_idinfo,
+ &lsiraid_idinfo,
+ &viaraid_idinfo,
+ &silraid_idinfo,
+ &nvraid_idinfo,
+ &pdcraid_idinfo,
+ &highpoint45x_idinfo,
+ &highpoint37x_idinfo,
+ &adraid_idinfo,
+ &jmraid_idinfo,
+
+ &drbd_idinfo,
+ &drbdproxy_datalog_idinfo,
+ &lvm2_idinfo,
+ &lvm1_idinfo,
+ &snapcow_idinfo,
+ &verity_hash_idinfo,
+ &luks_idinfo,
+ &vmfs_volume_idinfo,
+
+ /* Filesystems */
+ &vfat_idinfo,
+ &swsuspend_idinfo,
+ &swap_idinfo,
+ &xfs_idinfo,
+ &ext4dev_idinfo,
+ &ext4_idinfo,
+ &ext3_idinfo,
+ &ext2_idinfo,
+ &jbd_idinfo,
+ &reiser_idinfo,
+ &reiser4_idinfo,
+ &jfs_idinfo,
+ &udf_idinfo,
+ &iso9660_idinfo,
+ &zfs_idinfo,
+ &hfsplus_idinfo,
+ &hfs_idinfo,
+ &ufs_idinfo,
+ &hpfs_idinfo,
+ &sysv_idinfo,
+ &xenix_idinfo,
+ &ntfs_idinfo,
+ &cramfs_idinfo,
+ &romfs_idinfo,
+ &minix_idinfo,
+ &gfs_idinfo,
+ &gfs2_idinfo,
+ &ocfs_idinfo,
+ &ocfs2_idinfo,
+ &oracleasm_idinfo,
+ &vxfs_idinfo,
+ &squashfs_idinfo,
+ &netware_idinfo,
+ &btrfs_idinfo,
+ &ubifs_idinfo,
+ &bfs_idinfo,
+ &vmfs_fs_idinfo,
+ &befs_idinfo,
+ &nilfs2_idinfo,
+ &exfat_idinfo
+};
+
+/*
+ * Driver definition
+ */
+const struct blkid_chaindrv superblocks_drv = {
+ .id = BLKID_CHAIN_SUBLKS,
+ .name = "superblocks",
+ .dflt_enabled = TRUE,
+ .dflt_flags = BLKID_SUBLKS_DEFAULT,
+ .idinfos = idinfos,
+ .nidinfos = ARRAY_SIZE(idinfos),
+ .has_fltr = TRUE,
+ .probe = superblocks_probe,
+ .safeprobe = superblocks_safeprobe,
+};
+
+/**
+ * blkid_probe_enable_superblocks:
+ * @pr: probe
+ * @enable: TRUE/FALSE
+ *
+ * Enables/disables the superblocks probing for non-binary interface.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_enable_superblocks(blkid_probe pr, int enable)
+{
+ if (!pr)
+ return -1;
+ pr->chains[BLKID_CHAIN_SUBLKS].enabled = enable;
+ return 0;
+}
+
+/**
+ * blkid_probe_set_superblocks_flags:
+ * @pr: prober
+ * @flags: BLKID_SUBLKS_* flags
+ *
+ * Sets probing flags to the superblocks prober. This function is optional, the
+ * default are BLKID_SUBLKS_DEFAULTS flags.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags)
+{
+ if (!pr)
+ return -1;
+
+ pr->chains[BLKID_CHAIN_SUBLKS].flags = flags;
+ return 0;
+}
+
+/**
+ * blkid_probe_reset_superblocks_filter:
+ * @pr: prober
+ *
+ * Resets superblocks probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_reset_superblocks_filter(blkid_probe pr)
+{
+ return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_invert_superblocks_filter:
+ * @pr: prober
+ *
+ * Inverts superblocks probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_invert_superblocks_filter(blkid_probe pr)
+{
+ return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_filter_superblocks_type:
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @names: NULL terminated array of probing function names (e.g. "vfat").
+ *
+ * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @names;
+ *
+ * %BLKID_FLTR_ONLYIN - probe for items which are IN @names
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[])
+{
+ return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names);
+}
+
+/**
+ * blkid_probe_filter_superblocks_usage:
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @usage: BLKID_USAGE_* flags
+ *
+ * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @usage;
+ *
+ * %BLKID_FLTR_ONLYIN - probe for items which are IN @usage
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage)
+{
+ unsigned long *fltr;
+ struct blkid_chain *chn;
+ size_t i;
+
+ if (!pr)
+ return -1;
+
+ fltr = blkid_probe_get_filter(pr, BLKID_CHAIN_SUBLKS, TRUE);
+ if (!fltr)
+ return -1;
+
+ chn = &pr->chains[BLKID_CHAIN_SUBLKS];
+
+ for (i = 0; i < chn->driver->nidinfos; i++) {
+ const struct blkid_idinfo *id = chn->driver->idinfos[i];
+
+ if (id->usage & usage) {
+ if (flag & BLKID_FLTR_NOTIN)
+ blkid_bmp_set_item(chn->fltr, i);
+ } else if (flag & BLKID_FLTR_ONLYIN)
+ blkid_bmp_set_item(chn->fltr, i);
+ }
+ DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n"));
+ return 0;
+}
+
+/**
+ * blkid_known_fstype:
+ * @fstype: filesystem name
+ *
+ * Returns: 1 for known filesytems, or 0 for unknown filesystem.
+ */
+int blkid_known_fstype(const char *fstype)
+{
+ size_t i;
+
+ if (!fstype)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
+ const struct blkid_idinfo *id = idinfos[i];
+ if (strcmp(id->name, fstype) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * blkid_superblocks_get_name:
+ * @idx: number >= 0
+ * @name: returns name of supported filesystem/raid (optional)
+ * @usage: returns BLKID_USAGE_* flags, (optional)
+ *
+ * Returns: -1 if @idx is out of range, or 0 on success.
+ */
+int blkid_superblocks_get_name(size_t idx, const char **name, int *usage)
+{
+ if (idx < ARRAY_SIZE(idinfos)) {
+ if (name)
+ *name = idinfos[idx]->name;
+ if (usage)
+ *usage = idinfos[idx]->usage;
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * The blkid_do_probe() backend.
+ */
+static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn)
+{
+ size_t i;
+
+ if (!pr || chn->idx < -1)
+ return -1;
+ blkid_probe_chain_reset_vals(pr, chn);
+
+ DBG(DEBUG_LOWPROBE,
+ printf("--> starting probing loop [SUBLKS idx=%d]\n",
+ chn->idx));
+
+ if (pr->size <= 0 || (pr->size <= 1024 && !S_ISCHR(pr->mode)))
+ /* Ignore very very small block devices or regular files (e.g.
+ * extended partitions). Note that size of the UBI char devices
+ * is 1 byte */
+ goto nothing;
+
+ i = chn->idx < 0 ? 0 : chn->idx + 1U;
+
+ for ( ; i < ARRAY_SIZE(idinfos); i++) {
+ const struct blkid_idinfo *id;
+ const struct blkid_idmag *mag = NULL;
+ blkid_loff_t off = 0;
+ int rc = 0;
+
+ chn->idx = i;
+ id = idinfos[i];
+
+ if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) {
+ DBG(DEBUG_LOWPROBE, printf("filter out: %s\n", id->name));
+ continue;
+ }
+
+ if (id->minsz && id->minsz > pr->size)
+ continue; /* the device is too small */
+
+ /* don't probe for RAIDs, swap or journal on CD/DVDs */
+ if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) &&
+ blkid_probe_is_cdrom(pr))
+ continue;
+
+ /* don't probe for RAIDs on floppies */
+ if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr))
+ continue;
+
+ DBG(DEBUG_LOWPROBE, printf("[%zd] %s:\n", i, id->name));
+
+ if (blkid_probe_get_idmag(pr, id, &off, &mag))
+ continue;
+
+ /* final check by probing function */
+ if (id->probefunc) {
+ DBG(DEBUG_LOWPROBE, printf("\tcall probefunc()\n"));
+ if (id->probefunc(pr, mag) != 0) {
+ blkid_probe_chain_reset_vals(pr, chn);
+ continue;
+ }
+ }
+
+ /* all cheks passed */
+ if (chn->flags & BLKID_SUBLKS_TYPE)
+ rc = blkid_probe_set_value(pr, "TYPE",
+ (unsigned char *) id->name,
+ strlen(id->name) + 1);
+
+ if (!rc)
+ rc = blkid_probe_set_usage(pr, id->usage);
+
+ if (!rc && mag)
+ rc = blkid_probe_set_magic(pr, off, mag->len,
+ (unsigned char *) mag->magic);
+ if (rc) {
+ blkid_probe_chain_reset_vals(pr, chn);
+ DBG(DEBUG_LOWPROBE, printf("failed to set result -- ingnore\n"));
+ continue;
+ }
+
+ DBG(DEBUG_LOWPROBE,
+ printf("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]\n",
+ id->name, chn->idx));
+ return 0;
+ }
+
+nothing:
+ DBG(DEBUG_LOWPROBE,
+ printf("<-- leaving probing loop (failed) [SUBLKS idx=%d]\n",
+ chn->idx));
+ return 1;
+}
+
+/*
+ * This is the same function as blkid_do_probe(), but returns only one result
+ * (cannot be used in while()) and checks for ambivalen results (more
+ * filesystems on the device) -- in such case returns -2.
+ *
+ * The function does not check for filesystems when a RAID or crypto signature
+ * is detected. The function also does not check for collision between RAIDs
+ * and crypto devices. The first detected RAID or crypto device is returned.
+ *
+ * The function does not probe for ambivalent results on very small devices
+ * (e.g. floppies), on small devices the first detected filesystem is returned.
+ */
+static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
+{
+ struct blkid_prval vals[BLKID_NVALS_SUBLKS];
+ int nvals = BLKID_NVALS_SUBLKS;
+ int idx = -1;
+ int count = 0;
+ int intol = 0;
+ int rc;
+
+ while ((rc = superblocks_probe(pr, chn)) == 0) {
+
+ if (blkid_probe_is_tiny(pr) && !count)
+ /* floppy or so -- returns the first result. */
+ return 0;
+
+ count++;
+
+ if (chn->idx >= 0 &&
+ idinfos[chn->idx]->usage & (BLKID_USAGE_RAID | BLKID_USAGE_CRYPTO))
+ break;
+
+ if (chn->idx >= 0 &&
+ !(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT))
+ intol++;
+
+ if (count == 1) {
+ /* save the first result */
+ nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
+ idx = chn->idx;
+ }
+ }
+
+ if (rc < 0)
+ return rc; /* error */
+
+ if (count > 1 && intol) {
+ DBG(DEBUG_LOWPROBE,
+ printf("ERROR: superblocks chain: "
+ "ambivalent result detected (%d filesystems)!\n",
+ count));
+ return -2; /* error, ambivalent result (more FS) */
+ }
+ if (!count)
+ return 1; /* nothing detected */
+
+ if (idx != -1) {
+ /* restore the first result */
+ blkid_probe_chain_reset_vals(pr, chn);
+ blkid_probe_append_vals(pr, vals, nvals);
+ chn->idx = idx;
+ }
+
+ /*
+ * The RAID device could be partitioned. The problem are RAID1 devices
+ * where the partition table is visible from underlaying devices. We
+ * have to ignore such partition tables.
+ */
+ if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID)
+ pr->prob_flags |= BLKID_PROBE_FL_IGNORE_PT;
+
+ return 0;
+}
+
+int blkid_probe_set_version(blkid_probe pr, const char *version)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+ if (chn->flags & BLKID_SUBLKS_VERSION)
+ return blkid_probe_set_value(pr, "VERSION",
+ (unsigned char *) version, strlen(version) + 1);
+ return 0;
+}
+
+int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ int rc = 0;
+
+ if (chn->flags & BLKID_SUBLKS_VERSION) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap);
+ va_end(ap);
+ }
+ return rc;
+}
+
+static int blkid_probe_set_usage(blkid_probe pr, int usage)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ char *u = NULL;
+
+ if (!(chn->flags & BLKID_SUBLKS_USAGE))
+ return 0;
+
+ if (usage & BLKID_USAGE_FILESYSTEM)
+ u = "filesystem";
+ else if (usage & BLKID_USAGE_RAID)
+ u = "raid";
+ else if (usage & BLKID_USAGE_CRYPTO)
+ u = "crypto";
+ else if (usage & BLKID_USAGE_OTHER)
+ u = "other";
+ else
+ u = "unknown";
+
+ return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1);
+}
+
+int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ struct blkid_prval *v;
+ if (len > BLKID_PROBVAL_BUFSIZ)
+ len = BLKID_PROBVAL_BUFSIZ;
+
+ if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
+ blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
+ return -1;
+ if (!(chn->flags & BLKID_SUBLKS_LABEL))
+ return 0;
+ v = blkid_probe_assign_value(pr, "LABEL");
+ if (!v)
+ return -1;
+
+ if (len == BLKID_PROBVAL_BUFSIZ)
+ len--; /* make a space for \0 */
+
+ memcpy(v->data, label, len);
+ v->data[len] = '\0';
+
+ v->len = blkid_rtrim_whitespace(v->data) + 1;
+ if (v->len == 1)
+ blkid_probe_reset_last_value(pr);
+ return 0;
+}
+
+int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
+ size_t len, int enc)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ struct blkid_prval *v;
+
+ if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
+ blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
+ return -1;
+ if (!(chn->flags & BLKID_SUBLKS_LABEL))
+ return 0;
+ v = blkid_probe_assign_value(pr, "LABEL");
+ if (!v)
+ return -1;
+
+ blkid_encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
+ v->len = blkid_rtrim_whitespace(v->data) + 1;
+ if (v->len == 1)
+ blkid_probe_reset_last_value(pr);
+ return 0;
+}
+
+/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
+static int uuid_is_empty(const unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ if (buf[i])
+ return 0;
+ return 1;
+}
+
+int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
+ size_t len, const char *fmt, ...)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ int rc = -1;
+ va_list ap;
+
+ if (len > BLKID_PROBVAL_BUFSIZ)
+ len = BLKID_PROBVAL_BUFSIZ;
+
+ if (uuid_is_empty(uuid, len))
+ return 0;
+
+ if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
+ blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
+ return -1;
+ if (!(chn->flags & BLKID_SUBLKS_UUID))
+ return 0;
+
+ va_start(ap, fmt);
+ rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap);
+ va_end(ap);
+
+ /* convert to lower case (..be paranoid) */
+ if (!rc) {
+ size_t i;
+ struct blkid_prval *v = __blkid_probe_get_value(pr,
+ blkid_probe_numof_values(pr));
+ if (v) {
+ for (i = 0; i < v->len; i++)
+ if (v->data[i] >= 'A' && v->data[i] <= 'F')
+ v->data[i] = (v->data[i] - 'A') + 'a';
+ }
+ }
+ return rc;
+}
+
+/* function to set UUIDs that are in suberblocks stored as strings */
+int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ struct blkid_prval *v;
+
+ if (str == NULL || *str == '\0')
+ return -1;
+ if (!len)
+ len = strlen((char *) str);
+ if (len > BLKID_PROBVAL_BUFSIZ)
+ len = BLKID_PROBVAL_BUFSIZ;
+
+ if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
+ blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
+ return -1;
+ if (!(chn->flags & BLKID_SUBLKS_UUID))
+ return 0;
+
+ v = blkid_probe_assign_value(pr, "UUID");
+ if (v) {
+ if (len == BLKID_PROBVAL_BUFSIZ)
+ len--; /* make a space for \0 */
+
+ memcpy((char *) v->data, str, len);
+ v->data[len] = '\0';
+ v->len = len + 1;
+ return 0;
+ }
+ return -1;
+}
+
+/* default _set_uuid function to set DCE UUIDs */
+int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ struct blkid_prval *v;
+
+ if (uuid_is_empty(uuid, 16))
+ return 0;
+
+ if (!name) {
+ if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
+ blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
+ return -1;
+ if (!(chn->flags & BLKID_SUBLKS_UUID))
+ return 0;
+
+ v = blkid_probe_assign_value(pr, "UUID");
+ } else
+ v = blkid_probe_assign_value(pr, name);
+
+ blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
+ v->len = 37;
+
+ return 0;
+}
+
+int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)
+{
+ return blkid_probe_set_uuid_as(pr, uuid, NULL);
+}
+
+/**
+ * blkid_probe_set_request:
+ * @pr: probe
+ * @flags: BLKID_PROBREQ_* (deprecated) or BLKID_SUBLKS_* flags
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_set_superblocks_flags().
+ */
+int blkid_probe_set_request(blkid_probe pr, int flags)
+{
+ return blkid_probe_set_superblocks_flags(pr, flags);
+}
+
+/**
+ * blkid_probe_reset_filter:
+ * @pr: prober
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_reset_superblocks_filter().
+ */
+int blkid_probe_reset_filter(blkid_probe pr)
+{
+ return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_invert_filter:
+ * @pr: prober
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_invert_superblocks_filter().
+ */
+int blkid_probe_invert_filter(blkid_probe pr)
+{
+ return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_filter_types
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @names: NULL terminated array of probing function names (e.g. "vfat").
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_filter_superblocks_types().
+ */
+int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[])
+{
+ return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names);
+}
+
+/**
+ * blkid_probe_filter_usage
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @usage: BLKID_USAGE_* flags
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_filter_superblocks_usage().
+ */
+int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage)
+{
+ return blkid_probe_filter_superblocks_usage(pr, flag, usage);
+}
+
+
diff --git a/libblkid/src/superblocks/superblocks.h b/libblkid/src/superblocks/superblocks.h
new file mode 100644
index 0000000..08f1438
--- /dev/null
+++ b/libblkid/src/superblocks/superblocks.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef _BLKID_SUPERBLOCKS_H
+#define _BLKID_SUPERBLOCKS_H
+
+#include "blkidP.h"
+
+extern const struct blkid_idinfo cramfs_idinfo;
+extern const struct blkid_idinfo swap_idinfo;
+extern const struct blkid_idinfo swsuspend_idinfo;
+extern const struct blkid_idinfo adraid_idinfo;
+extern const struct blkid_idinfo ddfraid_idinfo;
+extern const struct blkid_idinfo iswraid_idinfo;
+extern const struct blkid_idinfo jmraid_idinfo;
+extern const struct blkid_idinfo lsiraid_idinfo;
+extern const struct blkid_idinfo nvraid_idinfo;
+extern const struct blkid_idinfo pdcraid_idinfo;
+extern const struct blkid_idinfo silraid_idinfo;
+extern const struct blkid_idinfo viaraid_idinfo;
+extern const struct blkid_idinfo linuxraid_idinfo;
+extern const struct blkid_idinfo ext4dev_idinfo;
+extern const struct blkid_idinfo ext4_idinfo;
+extern const struct blkid_idinfo ext3_idinfo;
+extern const struct blkid_idinfo ext2_idinfo;
+extern const struct blkid_idinfo jbd_idinfo;
+extern const struct blkid_idinfo jfs_idinfo;
+extern const struct blkid_idinfo xfs_idinfo;
+extern const struct blkid_idinfo gfs_idinfo;
+extern const struct blkid_idinfo gfs2_idinfo;
+extern const struct blkid_idinfo romfs_idinfo;
+extern const struct blkid_idinfo ocfs_idinfo;
+extern const struct blkid_idinfo ocfs2_idinfo;
+extern const struct blkid_idinfo oracleasm_idinfo;
+extern const struct blkid_idinfo reiser_idinfo;
+extern const struct blkid_idinfo reiser4_idinfo;
+extern const struct blkid_idinfo hfs_idinfo;
+extern const struct blkid_idinfo hfsplus_idinfo;
+extern const struct blkid_idinfo ntfs_idinfo;
+extern const struct blkid_idinfo iso9660_idinfo;
+extern const struct blkid_idinfo udf_idinfo;
+extern const struct blkid_idinfo vxfs_idinfo;
+extern const struct blkid_idinfo minix_idinfo;
+extern const struct blkid_idinfo vfat_idinfo;
+extern const struct blkid_idinfo ufs_idinfo;
+extern const struct blkid_idinfo hpfs_idinfo;
+extern const struct blkid_idinfo lvm2_idinfo;
+extern const struct blkid_idinfo lvm1_idinfo;
+extern const struct blkid_idinfo snapcow_idinfo;
+extern const struct blkid_idinfo verity_hash_idinfo;
+extern const struct blkid_idinfo luks_idinfo;
+extern const struct blkid_idinfo highpoint37x_idinfo;
+extern const struct blkid_idinfo highpoint45x_idinfo;
+extern const struct blkid_idinfo squashfs_idinfo;
+extern const struct blkid_idinfo netware_idinfo;
+extern const struct blkid_idinfo sysv_idinfo;
+extern const struct blkid_idinfo xenix_idinfo;
+extern const struct blkid_idinfo btrfs_idinfo;
+extern const struct blkid_idinfo ubifs_idinfo;
+extern const struct blkid_idinfo zfs_idinfo;
+extern const struct blkid_idinfo bfs_idinfo;
+extern const struct blkid_idinfo vmfs_volume_idinfo;
+extern const struct blkid_idinfo vmfs_fs_idinfo;
+extern const struct blkid_idinfo drbd_idinfo;
+extern const struct blkid_idinfo drbdproxy_datalog_idinfo;
+extern const struct blkid_idinfo befs_idinfo;
+extern const struct blkid_idinfo nilfs2_idinfo;
+extern const struct blkid_idinfo exfat_idinfo;
+
+/*
+ * superblock functions
+ */
+extern int blkid_probe_set_version(blkid_probe pr, const char *version);
+extern int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+
+extern int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len);
+extern int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
+ size_t len, int enc);
+extern int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
+ size_t len, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 4, 5)));
+extern int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len);
+
+extern int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid);
+extern int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name);
+
+
+#endif /* _BLKID_SUPERBLOCKS_H */
diff --git a/libblkid/src/superblocks/swap.c b/libblkid/src/superblocks/swap.c
new file mode 100644
index 0000000..7ac119b
--- /dev/null
+++ b/libblkid/src/superblocks/swap.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/* linux-2.6/include/linux/swap.h */
+struct swap_header_v1_2 {
+ /* char bootbits[1024]; */ /* Space for disklabel etc. */
+ uint32_t version;
+ uint32_t lastpage;
+ uint32_t nr_badpages;
+ unsigned char uuid[16];
+ unsigned char volume[16];
+ uint32_t padding[117];
+ uint32_t badpages[1];
+} __attribute__((packed));
+
+#define PAGESIZE_MIN 0xff6 /* 4086 (arm, i386, ...) */
+#define PAGESIZE_MAX 0xfff6 /* 65526 (ia64) */
+
+#define TOI_MAGIC_STRING "\xed\xc3\x02\xe9\x98\x56\xe5\x0c"
+#define TOI_MAGIC_STRLEN (sizeof(TOI_MAGIC_STRING) - 1)
+
+static int swap_set_info(blkid_probe pr, const char *version)
+{
+ struct swap_header_v1_2 *hdr;
+
+ /* Swap header always located at offset of 1024 bytes */
+ hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024,
+ sizeof(struct swap_header_v1_2));
+ if (!hdr)
+ return -1;
+
+ /* SWAPSPACE2 - check for wrong version or zeroed pagecount */
+ if (strcmp(version, "2") == 0 &&
+ (hdr->version != 1 || hdr->lastpage == 0))
+ return -1;
+
+ /* arbitrary sanity check.. is there any garbage down there? */
+ if (hdr->padding[32] == 0 && hdr->padding[33] == 0) {
+ if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume,
+ sizeof(hdr->volume)) < 0)
+ return -1;
+ if (blkid_probe_set_uuid(pr, hdr->uuid) < 0)
+ return -1;
+ }
+
+ blkid_probe_set_version(pr, version);
+ return 0;
+}
+
+static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ unsigned char *buf;
+
+ if (!mag)
+ return -1;
+
+ /* TuxOnIce keeps valid swap header at the end of the 1st page */
+ buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN);
+ if (!buf)
+ return -1;
+
+ if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0)
+ return 1; /* Ignore swap signature, it's TuxOnIce */
+
+ if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) {
+ /* swap v0 doesn't support LABEL or UUID */
+ blkid_probe_set_version(pr, "1");
+ return 0;
+
+ } else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len))
+ return swap_set_info(pr, "2");
+
+ return -1;
+}
+
+static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ if (!mag)
+ return -1;
+ if (!memcmp(mag->magic, "S1SUSPEND", mag->len))
+ return swap_set_info(pr, "s1suspend");
+ if (!memcmp(mag->magic, "S2SUSPEND", mag->len))
+ return swap_set_info(pr, "s2suspend");
+ if (!memcmp(mag->magic, "ULSUSPEND", mag->len))
+ return swap_set_info(pr, "ulsuspend");
+ if (!memcmp(mag->magic, TOI_MAGIC_STRING, mag->len))
+ return swap_set_info(pr, "tuxonice");
+ if (!memcmp(mag->magic, "LINHIB0001", mag->len))
+ return swap_set_info(pr, "linhib0001");
+
+ return -1; /* no signature detected */
+}
+
+const struct blkid_idinfo swap_idinfo =
+{
+ .name = "swap",
+ .usage = BLKID_USAGE_OTHER,
+ .probefunc = probe_swap,
+ .minsz = 10 * 4096, /* 10 pages */
+ .magics =
+ {
+ { "SWAP-SPACE", 10, 0, 0xff6 },
+ { "SWAPSPACE2", 10, 0, 0xff6 },
+ { "SWAP-SPACE", 10, 0, 0x1ff6 },
+ { "SWAPSPACE2", 10, 0, 0x1ff6 },
+ { "SWAP-SPACE", 10, 0, 0x3ff6 },
+ { "SWAPSPACE2", 10, 0, 0x3ff6 },
+ { "SWAP-SPACE", 10, 0, 0x7ff6 },
+ { "SWAPSPACE2", 10, 0, 0x7ff6 },
+ { "SWAP-SPACE", 10, 0, 0xfff6 },
+ { "SWAPSPACE2", 10, 0, 0xfff6 },
+ { NULL }
+ }
+};
+
+
+const struct blkid_idinfo swsuspend_idinfo =
+{
+ .name = "swsuspend",
+ .usage = BLKID_USAGE_OTHER,
+ .probefunc = probe_swsuspend,
+ .minsz = 10 * 4096, /* 10 pages */
+ .magics =
+ {
+ { TOI_MAGIC_STRING, TOI_MAGIC_STRLEN, 0, 0 },
+ { "S1SUSPEND", 9, 0, 0xff6 },
+ { "S2SUSPEND", 9, 0, 0xff6 },
+ { "ULSUSPEND", 9, 0, 0xff6 },
+ { "LINHIB0001",10,0, 0xff6 },
+
+ { "S1SUSPEND", 9, 0, 0x1ff6 },
+ { "S2SUSPEND", 9, 0, 0x1ff6 },
+ { "ULSUSPEND", 9, 0, 0x1ff6 },
+ { "LINHIB0001",10,0, 0x1ff6 },
+
+ { "S1SUSPEND", 9, 0, 0x3ff6 },
+ { "S2SUSPEND", 9, 0, 0x3ff6 },
+ { "ULSUSPEND", 9, 0, 0x3ff6 },
+ { "LINHIB0001",10,0, 0x3ff6 },
+
+ { "S1SUSPEND", 9, 0, 0x7ff6 },
+ { "S2SUSPEND", 9, 0, 0x7ff6 },
+ { "ULSUSPEND", 9, 0, 0x7ff6 },
+ { "LINHIB0001",10,0, 0x7ff6 },
+
+ { "S1SUSPEND", 9, 0, 0xfff6 },
+ { "S2SUSPEND", 9, 0, 0xfff6 },
+ { "ULSUSPEND", 9, 0, 0xfff6 },
+ { "LINHIB0001",10,0, 0xfff6 },
+
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/sysv.c b/libblkid/src/superblocks/sysv.c
new file mode 100644
index 0000000..80b0cc5
--- /dev/null
+++ b/libblkid/src/superblocks/sysv.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This is written from sratch according to Linux kernel fs/sysv/super.c file.
+ * It seems that sysv probing code in libvolume_id and also in the original
+ * blkid is useless.
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+#define XENIX_NICINOD 100
+#define XENIX_NICFREE 100
+
+struct xenix_super_block {
+ uint16_t s_isize;
+ uint32_t s_fsize;
+ uint16_t s_nfree;
+ uint32_t s_free[XENIX_NICFREE];
+ uint16_t s_ninode;
+ uint16_t s_inode[XENIX_NICINOD];
+ uint8_t s_flock;
+ uint8_t s_ilock;
+ uint8_t s_fmod;
+ uint8_t s_ronly;
+ uint32_t s_time;
+ uint32_t s_tfree;
+ uint16_t s_tinode;
+ uint16_t s_dinfo[4];
+ uint8_t s_fname[6];
+ uint8_t s_fpack[6];
+ uint8_t s_clean;
+ uint8_t s_fill[371];
+ uint32_t s_magic;
+ uint32_t s_type;
+} __attribute__((packed));
+
+
+#define SYSV_NICINOD 100
+#define SYSV_NICFREE 50
+
+struct sysv_super_block
+{
+ uint16_t s_isize;
+ uint16_t s_pad0;
+ uint32_t s_fsize;
+ uint16_t s_nfree;
+ uint16_t s_pad1;
+ uint32_t s_free[SYSV_NICFREE];
+ uint16_t s_ninode;
+ uint16_t s_pad2;
+ uint16_t s_inode[SYSV_NICINOD];
+ uint8_t s_flock;
+ uint8_t s_ilock;
+ uint8_t s_fmod;
+ uint8_t s_ronly;
+ uint32_t s_time;
+ uint16_t s_dinfo[4];
+ uint32_t s_tfree;
+ uint16_t s_tinode;
+ uint16_t s_pad3;
+ uint8_t s_fname[6];
+ uint8_t s_fpack[6];
+ uint32_t s_fill[12];
+ uint32_t s_state;
+ uint32_t s_magic;
+ uint32_t s_type;
+};
+
+static int probe_xenix(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct xenix_super_block *sb;
+
+ sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block);
+ if (!sb)
+ return -1;
+ blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname));
+ return 0;
+}
+
+#define SYSV_BLOCK_SIZE 1024
+
+/* Note that we don't probe for Coherent FS, this FS does not have
+ * magic string. (It requires to probe fname/fpack field..)
+ */
+static int probe_sysv(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct sysv_super_block *sb;
+ int blocks[] = {0, 9, 15, 18};
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(blocks); i++) {
+ int off = blocks[i] * SYSV_BLOCK_SIZE + SYSV_BLOCK_SIZE/2;
+
+ sb = (struct sysv_super_block *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct sysv_super_block));
+ if (!sb)
+ return -1;
+
+ if (sb->s_magic == cpu_to_le32(0xfd187e20) ||
+ sb->s_magic == cpu_to_be32(0xfd187e20)) {
+
+ if (blkid_probe_set_label(pr, sb->s_fname,
+ sizeof(sb->s_fname)))
+ return -1;
+
+ if (blkid_probe_set_magic(pr,
+ off + offsetof(struct sysv_super_block,
+ s_magic),
+ sizeof(sb->s_magic),
+ (unsigned char *) &sb->s_magic))
+ return -1;
+
+ return 0;
+ }
+ }
+ return 1;
+}
+
+const struct blkid_idinfo xenix_idinfo =
+{
+ .name = "xenix",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_xenix,
+ .magics =
+ {
+ { .magic = "\x2b\x55\x44", .len = 3, .kboff = 1, .sboff = 0x400 },
+ { .magic = "\x44\x55\x2b", .len = 3, .kboff = 1, .sboff = 0x400 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo sysv_idinfo =
+{
+ .name = "sysv",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_sysv,
+
+ /* SYSV is BE and LE and superblock could be on four positions. It's
+ * simpler to probe for the magic string by .probefunc().
+ */
+ .magics = BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/superblocks/ubifs.c b/libblkid/src/superblocks/ubifs.c
new file mode 100644
index 0000000..2d69c2b
--- /dev/null
+++ b/libblkid/src/superblocks/ubifs.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2009 Corentin Chary <corentincj@iksaif.net>
+ *
+ * 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 <stdint.h>
+
+#include "superblocks.h"
+
+/*
+ * struct ubifs_ch - common header node.
+ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
+ * @crc: CRC-32 checksum of the node header
+ * @sqnum: sequence number
+ * @len: full node length
+ * @node_type: node type
+ * @group_type: node group type
+ * @padding: reserved for future, zeroes
+ *
+ * Every UBIFS node starts with this common part. If the node has a key, the
+ * key always goes next.
+ */
+struct ubifs_ch {
+ uint32_t magic;
+ uint32_t crc;
+ uint64_t sqnum;
+ uint32_t len;
+ uint8_t node_type;
+ uint8_t group_type;
+ uint8_t padding[2];
+} __attribute__ ((packed));
+
+/*
+ * struct ubifs_sb_node - superblock node.
+ * @ch: common header
+ * @padding: reserved for future, zeroes
+ * @key_hash: type of hash function used in keys
+ * @key_fmt: format of the key
+ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc)
+ * @min_io_size: minimal input/output unit size
+ * @leb_size: logical eraseblock size in bytes
+ * @leb_cnt: count of LEBs used by file-system
+ * @max_leb_cnt: maximum count of LEBs used by file-system
+ * @max_bud_bytes: maximum amount of data stored in buds
+ * @log_lebs: log size in logical eraseblocks
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @orph_lebs: number of LEBs used for recording orphans
+ * @jhead_cnt: count of journal heads
+ * @fanout: tree fanout (max. number of links per indexing node)
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @fmt_version: UBIFS on-flash format version
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ * @padding1: reserved for future, zeroes
+ * @rp_uid: reserve pool UID
+ * @rp_gid: reserve pool GID
+ * @rp_size: size of the reserved pool in bytes
+ * @padding2: reserved for future, zeroes
+ * @time_gran: time granularity in nanoseconds
+ * @uuid: UUID generated when the file system image was created
+ * @ro_compat_version: UBIFS R/O compatibility version
+ */
+struct ubifs_sb_node {
+ struct ubifs_ch ch;
+ uint8_t padding[2];
+ uint8_t key_hash;
+ uint8_t key_fmt;
+ uint32_t flags;
+ uint32_t min_io_size;
+ uint32_t leb_size;
+ uint32_t leb_cnt;
+ uint32_t max_leb_cnt;
+ uint64_t max_bud_bytes;
+ uint32_t log_lebs;
+ uint32_t lpt_lebs;
+ uint32_t orph_lebs;
+ uint32_t jhead_cnt;
+ uint32_t fanout;
+ uint32_t lsave_cnt;
+ uint32_t fmt_version;
+ uint16_t default_compr;
+ uint8_t padding1[2];
+ uint32_t rp_uid;
+ uint32_t rp_gid;
+ uint64_t rp_size;
+ uint32_t time_gran;
+ uint8_t uuid[16];
+ uint32_t ro_compat_version;
+ uint8_t padding2[3968];
+} __attribute__ ((packed));
+
+static int probe_ubifs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct ubifs_sb_node *sb;
+
+ sb = blkid_probe_get_sb(pr, mag, struct ubifs_sb_node);
+ if (!sb)
+ return -1;
+
+ blkid_probe_set_uuid(pr, sb->uuid);
+ blkid_probe_sprintf_version(pr, "w%dr%d",
+ sb->fmt_version, sb->ro_compat_version);
+ return 0;
+}
+
+const struct blkid_idinfo ubifs_idinfo =
+{
+ .name = "ubifs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ubifs,
+ .magics =
+ {
+ { .magic = "\x31\x18\x10\x06", .len = 4 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/udf.c b/libblkid/src/superblocks/udf.c
new file mode 100644
index 0000000..a5afc5c
--- /dev/null
+++ b/libblkid/src/superblocks/udf.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct volume_descriptor {
+ struct descriptor_tag {
+ uint16_t id;
+ uint16_t version;
+ uint8_t checksum;
+ uint8_t reserved;
+ uint16_t serial;
+ uint16_t crc;
+ uint16_t crc_len;
+ uint32_t location;
+ } __attribute__((packed)) tag;
+
+ union {
+ struct anchor_descriptor {
+ uint32_t length;
+ uint32_t location;
+ } __attribute__((packed)) anchor;
+
+ struct primary_descriptor {
+ uint32_t seq_num;
+ uint32_t desc_num;
+ struct dstring {
+ uint8_t clen;
+ uint8_t c[31];
+ } __attribute__((packed)) ident;
+ } __attribute__((packed)) primary;
+
+ } __attribute__((packed)) type;
+
+} __attribute__((packed));
+
+struct volume_structure_descriptor {
+ uint8_t type;
+ uint8_t id[5];
+ uint8_t version;
+} __attribute__((packed));
+
+#define UDF_VSD_OFFSET 0x8000LL
+
+static int probe_udf(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct volume_descriptor *vd;
+ struct volume_structure_descriptor *vsd;
+ unsigned int bs;
+ unsigned int b;
+ unsigned int type;
+ unsigned int count;
+ unsigned int loc;
+
+ /* search Volume Sequence Descriptor (VSD) to get the logical
+ * block size of the volume */
+ for (bs = 0x800; bs < 0x8000; bs += 0x800) {
+ vsd = (struct volume_structure_descriptor *)
+ blkid_probe_get_buffer(pr,
+ UDF_VSD_OFFSET + bs,
+ sizeof(*vsd));
+ if (!vsd)
+ return 1;
+ if (vsd->id[0] != '\0')
+ goto nsr;
+ }
+ return -1;
+
+nsr:
+ /* search the list of VSDs for a NSR descriptor */
+ for (b = 0; b < 64; b++) {
+ vsd = (struct volume_structure_descriptor *)
+ blkid_probe_get_buffer(pr,
+ UDF_VSD_OFFSET + ((blkid_loff_t) b * bs),
+ sizeof(*vsd));
+ if (!vsd)
+ return -1;
+ if (vsd->id[0] == '\0')
+ return -1;
+ if (memcmp(vsd->id, "NSR02", 5) == 0)
+ goto anchor;
+ if (memcmp(vsd->id, "NSR03", 5) == 0)
+ goto anchor;
+ }
+ return -1;
+
+anchor:
+ /* read Anchor Volume Descriptor (AVDP) */
+ vd = (struct volume_descriptor *)
+ blkid_probe_get_buffer(pr, 256 * bs, sizeof(*vd));
+ if (!vd)
+ return -1;
+
+ type = le16_to_cpu(vd->tag.id);
+ if (type != 2) /* TAG_ID_AVDP */
+ return 0;
+
+ /* get desriptor list address and block count */
+ count = le32_to_cpu(vd->type.anchor.length) / bs;
+ loc = le32_to_cpu(vd->type.anchor.location);
+
+ /* pick the primary descriptor from the list */
+ for (b = 0; b < count; b++) {
+ vd = (struct volume_descriptor *)
+ blkid_probe_get_buffer(pr,
+ (blkid_loff_t) (loc + b) * bs,
+ sizeof(*vd));
+ if (!vd)
+ return -1;
+
+ type = le16_to_cpu(vd->tag.id);
+ if (type == 0)
+ break;
+ if (le32_to_cpu(vd->tag.location) != loc + b)
+ break;
+ if (type == 1) { /* TAG_ID_PVD */
+ uint8_t clen = vd->type.primary.ident.clen;
+
+ if (clen == 8)
+ blkid_probe_set_label(pr,
+ vd->type.primary.ident.c, 31);
+ else if (clen == 16)
+ blkid_probe_set_utf8label(pr,
+ vd->type.primary.ident.c,
+ 31, BLKID_ENC_UTF16BE);
+
+ if (clen == 8 || clen == 16)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+const struct blkid_idinfo udf_idinfo =
+{
+ .name = "udf",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_udf,
+ .flags = BLKID_IDINFO_TOLERANT,
+ .magics =
+ {
+ { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1 },
+ { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1 },
+ { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 },
+ { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1 },
+ { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1 },
+ { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1 },
+ { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/ufs.c b/libblkid/src/superblocks/ufs.c
new file mode 100644
index 0000000..673a528
--- /dev/null
+++ b/libblkid/src/superblocks/ufs.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+struct ufs_super_block {
+ uint32_t fs_link;
+ uint32_t fs_rlink;
+ uint32_t fs_sblkno;
+ uint32_t fs_cblkno;
+ uint32_t fs_iblkno;
+ uint32_t fs_dblkno;
+ uint32_t fs_cgoffset;
+ uint32_t fs_cgmask;
+ uint32_t fs_time;
+ uint32_t fs_size;
+ uint32_t fs_dsize;
+ uint32_t fs_ncg;
+ uint32_t fs_bsize;
+ uint32_t fs_fsize;
+ uint32_t fs_frag;
+ uint32_t fs_minfree;
+ uint32_t fs_rotdelay;
+ uint32_t fs_rps;
+ uint32_t fs_bmask;
+ uint32_t fs_fmask;
+ uint32_t fs_bshift;
+ uint32_t fs_fshift;
+ uint32_t fs_maxcontig;
+ uint32_t fs_maxbpg;
+ uint32_t fs_fragshift;
+ uint32_t fs_fsbtodb;
+ uint32_t fs_sbsize;
+ uint32_t fs_csmask;
+ uint32_t fs_csshift;
+ uint32_t fs_nindir;
+ uint32_t fs_inopb;
+ uint32_t fs_nspf;
+ uint32_t fs_optim;
+ uint32_t fs_npsect_state;
+ uint32_t fs_interleave;
+ uint32_t fs_trackskew;
+ uint32_t fs_id[2];
+ uint32_t fs_csaddr;
+ uint32_t fs_cssize;
+ uint32_t fs_cgsize;
+ uint32_t fs_ntrak;
+ uint32_t fs_nsect;
+ uint32_t fs_spc;
+ uint32_t fs_ncyl;
+ uint32_t fs_cpg;
+ uint32_t fs_ipg;
+ uint32_t fs_fpg;
+ struct ufs_csum {
+ uint32_t cs_ndir;
+ uint32_t cs_nbfree;
+ uint32_t cs_nifree;
+ uint32_t cs_nffree;
+ } fs_cstotal;
+ int8_t fs_fmod;
+ int8_t fs_clean;
+ int8_t fs_ronly;
+ int8_t fs_flags;
+ union {
+ struct {
+ int8_t fs_fsmnt[512];
+ uint32_t fs_cgrotor;
+ uint32_t fs_csp[31];
+ uint32_t fs_maxcluster;
+ uint32_t fs_cpc;
+ uint16_t fs_opostbl[16][8];
+ } fs_u1;
+ struct {
+ int8_t fs_fsmnt[468];
+ uint8_t fs_volname[32];
+ uint64_t fs_swuid;
+ int32_t fs_pad;
+ uint32_t fs_cgrotor;
+ uint32_t fs_ocsp[28];
+ uint32_t fs_contigdirs;
+ uint32_t fs_csp;
+ uint32_t fs_maxcluster;
+ uint32_t fs_active;
+ int32_t fs_old_cpc;
+ int32_t fs_maxbsize;
+ int64_t fs_sparecon64[17];
+ int64_t fs_sblockloc;
+ struct ufs2_csum_total {
+ uint64_t cs_ndir;
+ uint64_t cs_nbfree;
+ uint64_t cs_nifree;
+ uint64_t cs_nffree;
+ uint64_t cs_numclusters;
+ uint64_t cs_spare[3];
+ } fs_cstotal;
+ struct ufs_timeval {
+ int32_t tv_sec;
+ int32_t tv_usec;
+ } fs_time;
+ int64_t fs_size;
+ int64_t fs_dsize;
+ uint64_t fs_csaddr;
+ int64_t fs_pendingblocks;
+ int32_t fs_pendinginodes;
+ } __attribute__((packed)) fs_u2;
+ } fs_u11;
+ union {
+ struct {
+ int32_t fs_sparecon[53];
+ int32_t fs_reclaim;
+ int32_t fs_sparecon2[1];
+ int32_t fs_state;
+ uint32_t fs_qbmask[2];
+ uint32_t fs_qfmask[2];
+ } fs_sun;
+ struct {
+ int32_t fs_sparecon[53];
+ int32_t fs_reclaim;
+ int32_t fs_sparecon2[1];
+ uint32_t fs_npsect;
+ uint32_t fs_qbmask[2];
+ uint32_t fs_qfmask[2];
+ } fs_sunx86;
+ struct {
+ int32_t fs_sparecon[50];
+ int32_t fs_contigsumsize;
+ int32_t fs_maxsymlinklen;
+ int32_t fs_inodefmt;
+ uint32_t fs_maxfilesize[2];
+ uint32_t fs_qbmask[2];
+ uint32_t fs_qfmask[2];
+ int32_t fs_state;
+ } fs_44;
+ } fs_u2;
+ int32_t fs_postblformat;
+ int32_t fs_nrpos;
+ int32_t fs_postbloff;
+ int32_t fs_rotbloff;
+ uint32_t fs_magic;
+ uint8_t fs_space[1];
+} __attribute__((packed));
+
+#define UFS_MAGIC 0x00011954
+#define UFS2_MAGIC 0x19540119
+#define UFS_MAGIC_FEA 0x00195612
+#define UFS_MAGIC_LFN 0x00095014
+#define UFS_MAGIC_SEC 0x00612195
+#define UFS_MAGIC_4GB 0x05231994
+
+static int probe_ufs(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ int offsets[] = { 0, 8, 64, 256 };
+ uint32_t mags[] = {
+ UFS2_MAGIC, UFS_MAGIC, UFS_MAGIC_FEA, UFS_MAGIC_LFN,
+ UFS_MAGIC_SEC, UFS_MAGIC_4GB
+ };
+ size_t i;
+ uint32_t magic;
+ struct ufs_super_block *ufs;
+ int is_be;
+
+ for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+ uint32_t magLE, magBE;
+ size_t y;
+
+ ufs = (struct ufs_super_block *)
+ blkid_probe_get_buffer(pr,
+ offsets[i] * 1024,
+ sizeof(struct ufs_super_block));
+ if (!ufs)
+ return -1;
+
+ magBE = be32_to_cpu(ufs->fs_magic);
+ magLE = le32_to_cpu(ufs->fs_magic);
+
+ for (y = 0; y < ARRAY_SIZE(mags); y++) {
+ if (magLE == mags[y] || magBE == mags[y]) {
+ magic = mags[y];
+ is_be = (magBE == mags[y]);
+ goto found;
+ }
+ }
+ }
+
+ return 1;
+
+found:
+ if (magic == UFS2_MAGIC) {
+ blkid_probe_set_version(pr, "2");
+ blkid_probe_set_label(pr, ufs->fs_u11.fs_u2.fs_volname,
+ sizeof(ufs->fs_u11.fs_u2.fs_volname));
+ } else
+ blkid_probe_set_version(pr, "1");
+ if (ufs->fs_id[0] || ufs->fs_id[1])
+ {
+ if (is_be)
+ blkid_probe_sprintf_uuid(pr,
+ (unsigned char *) &ufs->fs_id,
+ sizeof(ufs->fs_id),
+ "%08x%08x",
+ be32_to_cpu(ufs->fs_id[0]),
+ be32_to_cpu(ufs->fs_id[1]));
+ else
+ blkid_probe_sprintf_uuid(pr,
+ (unsigned char *) &ufs->fs_id,
+ sizeof(ufs->fs_id),
+ "%08x%08x",
+ le32_to_cpu(ufs->fs_id[0]),
+ le32_to_cpu(ufs->fs_id[1]));
+ }
+
+ if (blkid_probe_set_magic(pr,
+ (offsets[i] * 1024) +
+ offsetof(struct ufs_super_block, fs_magic),
+ sizeof(ufs->fs_magic),
+ (unsigned char *) &ufs->fs_magic))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * According to libvolume_id the UFS superblock could be on four positions.
+ * The original libblkid has checked one position (.kboff=8) only.
+ *
+ * We know four UFS magic strings and UFS could be both little-endian and
+ * big-endian. ... so we have:
+ *
+ * 4 position * 4 string * 2 version = 32 magic strings
+ *
+ * It seems simpler to check for these string in probing function that hardcode
+ * all in the .magic array.
+ */
+const struct blkid_idinfo ufs_idinfo =
+{
+ .name = "ufs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_ufs,
+ .magics = BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/superblocks/vfat.c b/libblkid/src/superblocks/vfat.c
new file mode 100644
index 0000000..2feb818
--- /dev/null
+++ b/libblkid/src/superblocks/vfat.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/* Yucky misaligned values */
+struct vfat_super_block {
+/* 00*/ unsigned char vs_ignored[3];
+/* 03*/ unsigned char vs_sysid[8];
+/* 0b*/ unsigned char vs_sector_size[2];
+/* 0d*/ uint8_t vs_cluster_size;
+/* 0e*/ uint16_t vs_reserved;
+/* 10*/ uint8_t vs_fats;
+/* 11*/ unsigned char vs_dir_entries[2];
+/* 13*/ unsigned char vs_sectors[2];
+/* 15*/ unsigned char vs_media;
+/* 16*/ uint16_t vs_fat_length;
+/* 18*/ uint16_t vs_secs_track;
+/* 1a*/ uint16_t vs_heads;
+/* 1c*/ uint32_t vs_hidden;
+/* 20*/ uint32_t vs_total_sect;
+/* 24*/ uint32_t vs_fat32_length;
+/* 28*/ uint16_t vs_flags;
+/* 2a*/ uint8_t vs_version[2];
+/* 2c*/ uint32_t vs_root_cluster;
+/* 30*/ uint16_t vs_fsinfo_sector;
+/* 32*/ uint16_t vs_backup_boot;
+/* 34*/ uint16_t vs_reserved2[6];
+/* 40*/ unsigned char vs_unknown[3];
+/* 43*/ unsigned char vs_serno[4];
+/* 47*/ unsigned char vs_label[11];
+/* 52*/ unsigned char vs_magic[8];
+/* 5a*/ unsigned char vs_dummy2[0x1fe - 0x5a];
+/*1fe*/ unsigned char vs_pmagic[2];
+} __attribute__((packed));
+
+/* Yucky misaligned values */
+struct msdos_super_block {
+/* 00*/ unsigned char ms_ignored[3];
+/* 03*/ unsigned char ms_sysid[8];
+/* 0b*/ unsigned char ms_sector_size[2];
+/* 0d*/ uint8_t ms_cluster_size;
+/* 0e*/ uint16_t ms_reserved;
+/* 10*/ uint8_t ms_fats;
+/* 11*/ unsigned char ms_dir_entries[2];
+/* 13*/ unsigned char ms_sectors[2]; /* =0 iff V3 or later */
+/* 15*/ unsigned char ms_media;
+/* 16*/ uint16_t ms_fat_length; /* Sectors per FAT */
+/* 18*/ uint16_t ms_secs_track;
+/* 1a*/ uint16_t ms_heads;
+/* 1c*/ uint32_t ms_hidden;
+/* V3 BPB */
+/* 20*/ uint32_t ms_total_sect; /* iff ms_sectors == 0 */
+/* V4 BPB */
+/* 24*/ unsigned char ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */
+/* 27*/ unsigned char ms_serno[4];
+/* 2b*/ unsigned char ms_label[11];
+/* 36*/ unsigned char ms_magic[8];
+/* 3e*/ unsigned char ms_dummy2[0x1fe - 0x3e];
+/*1fe*/ unsigned char ms_pmagic[2];
+} __attribute__((packed));
+
+struct vfat_dir_entry {
+ uint8_t name[11];
+ uint8_t attr;
+ uint16_t time_creat;
+ uint16_t date_creat;
+ uint16_t time_acc;
+ uint16_t date_acc;
+ uint16_t cluster_high;
+ uint16_t time_write;
+ uint16_t date_write;
+ uint16_t cluster_low;
+ uint32_t size;
+} __attribute__((packed));
+
+struct fat32_fsinfo {
+ uint8_t signature1[4];
+ uint32_t reserved1[120];
+ uint8_t signature2[4];
+ uint32_t free_clusters;
+ uint32_t next_cluster;
+ uint32_t reserved2[4];
+} __attribute__((packed));
+
+/* maximum number of clusters */
+#define FAT12_MAX 0xFF4
+#define FAT16_MAX 0xFFF4
+#define FAT32_MAX 0x0FFFFFF6
+
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIR 0x10
+#define FAT_ATTR_LONG_NAME 0x0f
+#define FAT_ATTR_MASK 0x3f
+#define FAT_ENTRY_FREE 0xe5
+
+static const char *no_name = "NO NAME ";
+
+#define unaligned_le16(x) \
+ (((unsigned char *) x)[0] + (((unsigned char *) x)[1] << 8))
+
+/*
+ * Look for LABEL (name) in the FAT root directory.
+ */
+static unsigned char *search_fat_label(blkid_probe pr,
+ uint64_t offset, uint32_t entries)
+{
+ struct vfat_dir_entry *ent, *dir = NULL;
+ uint32_t i;
+
+ DBG(DEBUG_LOWPROBE,
+ printf("\tlook for label in root-dir "
+ "(entries: %d, offset: %jd)\n", entries, offset));
+
+ if (!blkid_probe_is_tiny(pr)) {
+ /* large disk, read whole root directory */
+ dir = (struct vfat_dir_entry *)
+ blkid_probe_get_buffer(pr,
+ offset,
+ (blkid_loff_t) entries *
+ sizeof(struct vfat_dir_entry));
+ if (!dir)
+ return NULL;
+ }
+
+ for (i = 0; i < entries; i++) {
+ /*
+ * The root directory could be relatively large (4-16kB).
+ * Fortunately, the LABEL is usually the first entry in the
+ * directory. On tiny disks we call read() per entry.
+ */
+ if (!dir)
+ ent = (struct vfat_dir_entry *)
+ blkid_probe_get_buffer(pr,
+ (blkid_loff_t) offset + (i *
+ sizeof(struct vfat_dir_entry)),
+ sizeof(struct vfat_dir_entry));
+ else
+ ent = &dir[i];
+
+ if (!ent || ent->name[0] == 0x00)
+ break;
+
+ if ((ent->name[0] == FAT_ENTRY_FREE) ||
+ (ent->cluster_high != 0 || ent->cluster_low != 0) ||
+ ((ent->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME))
+ continue;
+
+ if ((ent->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) ==
+ FAT_ATTR_VOLUME_ID) {
+ DBG(DEBUG_LOWPROBE,
+ printf("\tfound fs LABEL at entry %d\n", i));
+ return ent->name;
+ }
+ }
+ return NULL;
+}
+
+static int fat_valid_superblock(const struct blkid_idmag *mag,
+ struct msdos_super_block *ms,
+ struct vfat_super_block *vs,
+ uint32_t *cluster_count, uint32_t *fat_size)
+{
+ uint16_t sector_size, dir_entries, reserved;
+ uint32_t sect_count, __fat_size, dir_size, __cluster_count, fat_length;
+ uint32_t max_count;
+
+ /* extra check for FATs without magic strings */
+ if (mag->len <= 2) {
+ /* Old floppies have a valid MBR signature */
+ if (ms->ms_pmagic[0] != 0x55 || ms->ms_pmagic[1] != 0xAA)
+ return 0;
+
+ /*
+ * OS/2 and apparently DFSee will place a FAT12/16-like
+ * pseudo-superblock in the first 512 bytes of non-FAT
+ * filesystems --- at least JFS and HPFS, and possibly others.
+ * So we explicitly check for those filesystems at the
+ * FAT12/16 filesystem magic field identifier, and if they are
+ * present, we rule this out as a FAT filesystem, despite the
+ * FAT-like pseudo-header.
+ */
+ if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) ||
+ (memcmp(ms->ms_magic, "HPFS ", 8) == 0))
+ return 0;
+ }
+
+ /* fat counts(Linux kernel expects at least 1 FAT table) */
+ if (!ms->ms_fats)
+ return 0;
+ if (!ms->ms_reserved)
+ return 0;
+ if (!(0xf8 <= ms->ms_media || ms->ms_media == 0xf0))
+ return 0;
+ if (!is_power_of_2(ms->ms_cluster_size))
+ return 0;
+
+ sector_size = unaligned_le16(&ms->ms_sector_size);
+ if (!is_power_of_2(sector_size) ||
+ sector_size < 512 || sector_size > 4096)
+ return 0;
+
+ dir_entries = unaligned_le16(&ms->ms_dir_entries);
+ reserved = le16_to_cpu(ms->ms_reserved);
+ sect_count = unaligned_le16(&ms->ms_sectors);
+
+ if (sect_count == 0)
+ sect_count = le32_to_cpu(ms->ms_total_sect);
+
+ fat_length = le16_to_cpu(ms->ms_fat_length);
+ if (fat_length == 0)
+ fat_length = le32_to_cpu(vs->vs_fat32_length);
+
+ __fat_size = fat_length * ms->ms_fats;
+ dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
+ (sector_size-1)) / sector_size;
+
+ __cluster_count = (sect_count - (reserved + __fat_size + dir_size)) /
+ ms->ms_cluster_size;
+ if (!ms->ms_fat_length && vs->vs_fat32_length)
+ max_count = FAT32_MAX;
+ else
+ max_count = __cluster_count > FAT12_MAX ? FAT16_MAX : FAT12_MAX;
+
+ if (__cluster_count > max_count)
+ return 0;
+
+ if (fat_size)
+ *fat_size = __fat_size;
+ if (cluster_count)
+ *cluster_count = __cluster_count;
+
+ return 1; /* valid */
+}
+
+/*
+ * This function is used by MBR partition table parser to avoid
+ * misinterpretation of FAT filesystem.
+ */
+int blkid_probe_is_vfat(blkid_probe pr)
+{
+ struct vfat_super_block *vs;
+ struct msdos_super_block *ms;
+ const struct blkid_idmag *mag = NULL;
+
+ if (blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag) || !mag)
+ return 0;
+
+ ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
+ if (!ms)
+ return 0;
+ vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
+ if (!vs)
+ return 0;
+
+ return fat_valid_superblock(mag, ms, vs, NULL, NULL);
+}
+
+/* FAT label extraction from the root directory taken from Kay
+ * Sievers's volume_id library */
+static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct vfat_super_block *vs;
+ struct msdos_super_block *ms;
+ const unsigned char *vol_label = 0;
+ unsigned char *vol_serno = NULL, vol_label_buf[11];
+ uint16_t sector_size = 0, reserved;
+ uint32_t cluster_count, fat_size;
+ const char *version = NULL;
+
+ ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
+ if (!ms)
+ return 0;
+ vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
+ if (!vs)
+ return 0;
+ if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size))
+ return 1;
+
+ sector_size = unaligned_le16(&ms->ms_sector_size);
+ reserved = le16_to_cpu(ms->ms_reserved);
+
+ if (ms->ms_fat_length) {
+ /* the label may be an attribute in the root directory */
+ uint32_t root_start = (reserved + fat_size) * sector_size;
+ uint32_t root_dir_entries = unaligned_le16(&vs->vs_dir_entries);
+
+ vol_label = search_fat_label(pr, root_start, root_dir_entries);
+ if (vol_label) {
+ memcpy(vol_label_buf, vol_label, 11);
+ vol_label = vol_label_buf;
+ }
+
+ if (!vol_label || !memcmp(vol_label, no_name, 11))
+ vol_label = ms->ms_label;
+ vol_serno = ms->ms_serno;
+
+ blkid_probe_set_value(pr, "SEC_TYPE", (unsigned char *) "msdos",
+ sizeof("msdos"));
+
+ if (cluster_count < FAT12_MAX)
+ version = "FAT12";
+ else if (cluster_count < FAT16_MAX)
+ version = "FAT16";
+
+ } else if (vs->vs_fat32_length) {
+ unsigned char *buf;
+ uint16_t fsinfo_sect;
+ int maxloop = 100;
+
+ /* Search the FAT32 root dir for the label attribute */
+ uint32_t buf_size = vs->vs_cluster_size * sector_size;
+ uint32_t start_data_sect = reserved + fat_size;
+ uint32_t entries = le32_to_cpu(vs->vs_fat32_length) *
+ sector_size / sizeof(uint32_t);
+ uint32_t next = le32_to_cpu(vs->vs_root_cluster);
+
+ while (next && next < entries && --maxloop) {
+ uint32_t next_sect_off;
+ uint64_t next_off, fat_entry_off;
+ int count;
+
+ next_sect_off = (next - 2) * vs->vs_cluster_size;
+ next_off = (uint64_t)(start_data_sect + next_sect_off) *
+ sector_size;
+
+ count = buf_size / sizeof(struct vfat_dir_entry);
+
+ vol_label = search_fat_label(pr, next_off, count);
+ if (vol_label) {
+ memcpy(vol_label_buf, vol_label, 11);
+ vol_label = vol_label_buf;
+ break;
+ }
+
+ /* get FAT entry */
+ fat_entry_off = ((uint64_t) reserved * sector_size) +
+ (next * sizeof(uint32_t));
+ buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size);
+ if (buf == NULL)
+ break;
+
+ /* set next cluster */
+ next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff;
+ }
+
+ version = "FAT32";
+
+ if (!vol_label || !memcmp(vol_label, no_name, 11))
+ vol_label = vs->vs_label;
+ vol_serno = vs->vs_serno;
+
+ /*
+ * FAT32 should have a valid signature in the fsinfo block,
+ * but also allow all bytes set to '\0', because some volumes
+ * do not set the signature at all.
+ */
+ fsinfo_sect = le16_to_cpu(vs->vs_fsinfo_sector);
+ if (fsinfo_sect) {
+ struct fat32_fsinfo *fsinfo;
+
+ buf = blkid_probe_get_buffer(pr,
+ (blkid_loff_t) fsinfo_sect * sector_size,
+ sizeof(struct fat32_fsinfo));
+ if (buf == NULL)
+ return -1;
+
+ fsinfo = (struct fat32_fsinfo *) buf;
+ if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 &&
+ memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 &&
+ memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0)
+ return -1;
+ if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 &&
+ memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0)
+ return -1;
+ }
+ }
+
+ if (vol_label && memcmp(vol_label, no_name, 11))
+ blkid_probe_set_label(pr, (unsigned char *) vol_label, 11);
+
+ /* We can't just print them as %04X, because they are unaligned */
+ if (vol_serno)
+ blkid_probe_sprintf_uuid(pr, vol_serno, 4, "%02X%02X-%02X%02X",
+ vol_serno[3], vol_serno[2], vol_serno[1], vol_serno[0]);
+ if (version)
+ blkid_probe_set_version(pr, version);
+
+ return 0;
+}
+
+
+const struct blkid_idinfo vfat_idinfo =
+{
+ .name = "vfat",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_vfat,
+ .magics =
+ {
+ { .magic = "MSWIN", .len = 5, .sboff = 0x52 },
+ { .magic = "FAT32 ", .len = 8, .sboff = 0x52 },
+ { .magic = "MSDOS", .len = 5, .sboff = 0x36 },
+ { .magic = "FAT16 ", .len = 8, .sboff = 0x36 },
+ { .magic = "FAT12 ", .len = 8, .sboff = 0x36 },
+ { .magic = "FAT ", .len = 8, .sboff = 0x36 },
+ { .magic = "\353", .len = 1, },
+ { .magic = "\351", .len = 1, },
+ { .magic = "\125\252", .len = 2, .sboff = 0x1fe },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/via_raid.c b/libblkid/src/superblocks/via_raid.c
new file mode 100644
index 0000000..eba7e4b
--- /dev/null
+++ b/libblkid/src/superblocks/via_raid.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct via_metadata {
+ uint16_t signature;
+ uint8_t version_number;
+ struct via_array {
+ uint16_t disk_bit_mask;
+ uint8_t disk_array_ex;
+ uint32_t capacity_low;
+ uint32_t capacity_high;
+ uint32_t serial_checksum;
+ } __attribute__((packed)) array;
+ uint32_t serial_checksum[8];
+ uint8_t checksum;
+} __attribute__((packed));
+
+#define VIA_SIGNATURE 0xAA55
+
+/* 8 bit checksum on first 50 bytes of metadata. */
+static uint8_t via_checksum(struct via_metadata *v)
+{
+ uint8_t i = 50, cs = 0;
+
+ while (i--)
+ cs += ((uint8_t*) v)[i];
+
+ return cs == v->checksum;
+}
+
+static int probe_viaraid(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t off;
+ struct via_metadata *v;
+
+ if (pr->size < 0x10000)
+ return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
+
+ off = ((pr->size / 0x200)-1) * 0x200;
+
+ v = (struct via_metadata *)
+ blkid_probe_get_buffer(pr,
+ off,
+ sizeof(struct via_metadata));
+ if (!v)
+ return -1;
+ if (le16_to_cpu(v->signature) != VIA_SIGNATURE)
+ return -1;
+ if (v->version_number > 2)
+ return -1;
+ if (!via_checksum(v))
+ return -1;
+ if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0)
+ return -1;
+ if (blkid_probe_set_magic(pr, off,
+ sizeof(v->signature),
+ (unsigned char *) &v->signature))
+ return -1;
+ return 0;
+}
+
+const struct blkid_idinfo viaraid_idinfo = {
+ .name = "via_raid_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_viaraid,
+ .magics = BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/vmfs.c b/libblkid/src/superblocks/vmfs.c
new file mode 100644
index 0000000..ead09a8
--- /dev/null
+++ b/libblkid/src/superblocks/vmfs.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 Mike Hommey <mh@glandium.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include "superblocks.h"
+
+struct vmfs_fs_info {
+ uint32_t magic;
+ uint32_t volume_version;
+ uint8_t version;
+ uint8_t uuid[16];
+ uint32_t mode;
+ char label[128];
+} __attribute__ ((__packed__));
+
+struct vmfs_volume_info {
+ uint32_t magic;
+ uint32_t ver;
+ uint8_t irrelevant[122];
+ uint8_t uuid[16];
+} __attribute__ ((__packed__));
+
+static int probe_vmfs_fs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct vmfs_fs_info *header;
+
+ header = blkid_probe_get_sb(pr, mag, struct vmfs_fs_info);
+ if (header == NULL)
+ return -1;
+
+ blkid_probe_sprintf_uuid(pr, (unsigned char *) header->uuid, 16,
+ "%02x%02x%02x%02x-%02x%02x%02x%02x-"
+ "%02x%02x-%02x%02x%02x%02x%02x%02x",
+ header->uuid[3], header->uuid[2], header->uuid[1],
+ header->uuid[0], header->uuid[7], header->uuid[6],
+ header->uuid[5], header->uuid[4], header->uuid[9],
+ header->uuid[8], header->uuid[10], header->uuid[11],
+ header->uuid[12], header->uuid[13], header->uuid[14],
+ header->uuid[15]);
+
+ blkid_probe_set_label(pr, (unsigned char *) header->label,
+ sizeof(header->label));
+ blkid_probe_sprintf_version(pr, "%u", header->version);
+ return 0;
+}
+
+static int probe_vmfs_volume(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct vmfs_volume_info *header;
+ unsigned char *lvm_uuid;
+
+ header = blkid_probe_get_sb(pr, mag, struct vmfs_volume_info);
+ if (header == NULL)
+ return -1;
+
+ blkid_probe_sprintf_value(pr, "UUID_SUB",
+ "%02x%02x%02x%02x-%02x%02x%02x%02x-"
+ "%02x%02x-%02x%02x%02x%02x%02x%02x",
+ header->uuid[3], header->uuid[2], header->uuid[1],
+ header->uuid[0], header->uuid[7], header->uuid[6],
+ header->uuid[5], header->uuid[4], header->uuid[9],
+ header->uuid[8], header->uuid[10], header->uuid[11],
+ header->uuid[12], header->uuid[13], header->uuid[14],
+ header->uuid[15]);
+ blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(header->ver));
+
+ lvm_uuid = blkid_probe_get_buffer(pr,
+ 1024 * 1024 /* Start of the volume info */
+ + 512 /* Offset to lvm info */
+ + 20 /* Offset in lvm info */, 35);
+ if (lvm_uuid)
+ blkid_probe_strncpy_uuid(pr, lvm_uuid, 35);
+
+ return 0;
+}
+
+const struct blkid_idinfo vmfs_fs_idinfo =
+{
+ .name = "VMFS",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_vmfs_fs,
+ .magics =
+ {
+ { .magic = "\x5e\xf1\xab\x2f", .len = 4, .kboff = 2048 },
+ { NULL }
+ }
+};
+
+const struct blkid_idinfo vmfs_volume_idinfo =
+{
+ .name = "VMFS_volume_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_vmfs_volume,
+ .magics =
+ {
+ { .magic = "\x0d\xd0\x01\xc0", .len = 4, .kboff = 1024 },
+ { NULL }
+ }
+};
diff --git a/libblkid/src/superblocks/vxfs.c b/libblkid/src/superblocks/vxfs.c
new file mode 100644
index 0000000..fdab85a
--- /dev/null
+++ b/libblkid/src/superblocks/vxfs.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+
+#include "superblocks.h"
+
+struct vxfs_super_block {
+ uint32_t vs_magic;
+ int32_t vs_version;
+};
+
+static int probe_vxfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct vxfs_super_block *vxs;
+
+ vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block);
+ if (!vxs)
+ return -1;
+
+ blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version);
+ return 0;
+}
+
+
+const struct blkid_idinfo vxfs_idinfo =
+{
+ .name = "vxfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_vxfs,
+ .magics =
+ {
+ { .magic = "\365\374\001\245", .len = 4, .kboff = 1 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/xfs.c b/libblkid/src/superblocks/xfs.c
new file mode 100644
index 0000000..1399fe1
--- /dev/null
+++ b/libblkid/src/superblocks/xfs.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct xfs_super_block {
+ unsigned char xs_magic[4];
+ uint32_t xs_blocksize;
+ uint64_t xs_dblocks;
+ uint64_t xs_rblocks;
+ uint32_t xs_dummy1[2];
+ unsigned char xs_uuid[16];
+ uint32_t xs_dummy2[15];
+ char xs_fname[12];
+ uint32_t xs_dummy3[2];
+ uint64_t xs_icount;
+ uint64_t xs_ifree;
+ uint64_t xs_fdblocks;
+} __attribute__((packed));
+
+static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct xfs_super_block *xs;
+
+ xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block);
+ if (!xs)
+ return -1;
+
+ if (strlen(xs->xs_fname))
+ blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname,
+ sizeof(xs->xs_fname));
+ blkid_probe_set_uuid(pr, xs->xs_uuid);
+ return 0;
+}
+
+const struct blkid_idinfo xfs_idinfo =
+{
+ .name = "xfs",
+ .usage = BLKID_USAGE_FILESYSTEM,
+ .probefunc = probe_xfs,
+ .magics =
+ {
+ { .magic = "XFSB", .len = 4 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
new file mode 100644
index 0000000..b96c5df
--- /dev/null
+++ b/libblkid/src/superblocks/zfs.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2009-2010 by Andreas Dilger <adilger@sun.com>
+ *
+ * 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 <errno.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "superblocks.h"
+
+#define VDEV_LABEL_UBERBLOCK (128 * 1024ULL)
+#define VDEV_LABEL_NVPAIR ( 16 * 1024ULL)
+#define VDEV_LABEL_SIZE (256 * 1024ULL)
+
+/* #include <sys/uberblock_impl.h> */
+#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */
+struct zfs_uberblock {
+ uint64_t ub_magic; /* UBERBLOCK_MAGIC */
+ uint64_t ub_version; /* SPA_VERSION */
+ uint64_t ub_txg; /* txg of last sync */
+ uint64_t ub_guid_sum; /* sum of all vdev guids */
+ uint64_t ub_timestamp; /* UTC time of last sync */
+ char ub_rootbp; /* MOS objset_phys_t */
+} __attribute__((packed));
+
+#define ZFS_TRIES 64
+#define ZFS_WANT 4
+
+#define DATA_TYPE_UINT64 8
+#define DATA_TYPE_STRING 9
+
+struct nvpair {
+ uint32_t nvp_size;
+ uint32_t nvp_unkown;
+ uint32_t nvp_namelen;
+ char nvp_name[0]; /* aligned to 4 bytes */
+ /* aligned ptr array for string arrays */
+ /* aligned array of data for value */
+};
+
+struct nvstring {
+ uint32_t nvs_type;
+ uint32_t nvs_elem;
+ uint32_t nvs_strlen;
+ unsigned char nvs_string[0];
+};
+
+struct nvuint64 {
+ uint32_t nvu_type;
+ uint32_t nvu_elem;
+ uint64_t nvu_value;
+};
+
+struct nvlist {
+ uint32_t nvl_unknown[3];
+ struct nvpair nvl_nvpair;
+};
+
+#define nvdebug(fmt, ...) do { } while(0)
+/*#define nvdebug(fmt, a...) printf(fmt, ##a)*/
+
+static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+{
+ struct nvlist *nvl;
+ struct nvpair *nvp;
+ size_t left = 4096;
+ int found = 0;
+
+ offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR;
+
+ /* Note that we currently assume that the desired fields are within
+ * the first 4k (left) of the nvlist. This is true for all pools
+ * I've seen, and simplifies this code somewhat, because we don't
+ * have to handle an nvpair crossing a buffer boundary. */
+ nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left);
+ if (nvl == NULL)
+ return;
+
+ nvdebug("zfs_extract: nvlist offset %llu\n", offset);
+
+ nvp = &nvl->nvl_nvpair;
+ while (left > sizeof(*nvp) && nvp->nvp_size != 0 && found < 3) {
+ int avail; /* tracks that name/value data fits in nvp_size */
+ int namesize;
+
+ nvp->nvp_size = be32_to_cpu(nvp->nvp_size);
+ nvp->nvp_namelen = be32_to_cpu(nvp->nvp_namelen);
+ avail = nvp->nvp_size - nvp->nvp_namelen - sizeof(*nvp);
+
+ nvdebug("left %zd nvp_size %u\n", left, nvp->nvp_size);
+ if (left < nvp->nvp_size || avail < 0)
+ break;
+
+ namesize = (nvp->nvp_namelen + 3) & ~3;
+
+ nvdebug("nvlist: size %u, namelen %u, name %*s\n",
+ nvp->nvp_size, nvp->nvp_namelen, nvp->nvp_namelen,
+ nvp->nvp_name);
+ if (strncmp(nvp->nvp_name, "name", nvp->nvp_namelen) == 0) {
+ struct nvstring *nvs = (void *)(nvp->nvp_name+namesize);
+
+ nvs->nvs_type = be32_to_cpu(nvs->nvs_type);
+ nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen);
+ avail -= nvs->nvs_strlen + sizeof(*nvs);
+ nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type,
+ nvs->nvs_strlen, nvs->nvs_string);
+ if (nvs->nvs_type == DATA_TYPE_STRING && avail >= 0)
+ blkid_probe_set_label(pr, nvs->nvs_string,
+ nvs->nvs_strlen);
+ found++;
+ } else if (strncmp(nvp->nvp_name, "guid",
+ nvp->nvp_namelen) == 0) {
+ struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize);
+ uint64_t nvu_value;
+
+ memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value));
+ nvu->nvu_type = be32_to_cpu(nvu->nvu_type);
+ nvu_value = be64_to_cpu(nvu_value);
+ avail -= sizeof(*nvu);
+ nvdebug("nvuint64: type %u value %"PRIu64"\n",
+ nvu->nvu_type, nvu_value);
+ if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0)
+ blkid_probe_sprintf_value(pr, "UUID_SUB",
+ "%"PRIu64, nvu_value);
+ found++;
+ } else if (strncmp(nvp->nvp_name, "pool_guid",
+ nvp->nvp_namelen) == 0) {
+ struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize);
+ uint64_t nvu_value;
+
+ memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value));
+ nvu->nvu_type = be32_to_cpu(nvu->nvu_type);
+ nvu_value = be64_to_cpu(nvu_value);
+ avail -= sizeof(*nvu);
+ nvdebug("nvuint64: type %u value %"PRIu64"\n",
+ nvu->nvu_type, nvu_value);
+ if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0)
+ blkid_probe_sprintf_uuid(pr, (unsigned char *)
+ &nvu_value,
+ sizeof(nvu_value),
+ "%"PRIu64, nvu_value);
+ found++;
+ }
+ if (left > nvp->nvp_size)
+ left -= nvp->nvp_size;
+ else
+ left = 0;
+ nvp = (struct nvpair *)((char *)nvp + nvp->nvp_size);
+ }
+}
+
+#define zdebug(fmt, ...) do {} while(0)
+/*#define zdebug(fmt, a...) printf(fmt, ##a)*/
+
+/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start
+ * of the disk, and 2 areas at the end of the disk. Check only some of them...
+ * #4 (@ 132kB) is the first one written on a new filesystem. */
+static int probe_zfs(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
+ struct zfs_uberblock *ub;
+ int swab_endian;
+ loff_t offset;
+ int tried;
+ int found;
+
+ zdebug("probe_zfs\n");
+ /* Look for at least 4 uberblocks to ensure a positive match */
+ for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK;
+ tried < ZFS_TRIES && found < ZFS_WANT;
+ tried++, offset += 4096) {
+ /* also try the second uberblock copy */
+ if (tried == (ZFS_TRIES / 2))
+ offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK;
+
+ ub = (struct zfs_uberblock *)
+ blkid_probe_get_buffer(pr, offset,
+ sizeof(struct zfs_uberblock));
+ if (ub == NULL)
+ return -1;
+
+ if (ub->ub_magic == UBERBLOCK_MAGIC)
+ found++;
+
+ if ((swab_endian = (ub->ub_magic == swab_magic)))
+ found++;
+
+ zdebug("probe_zfs: found %s-endian uberblock at %llu\n",
+ swab_endian ? "big" : "little", offset >> 10);
+ }
+
+ if (found < 4)
+ return -1;
+
+ /* If we found the 4th uberblock, then we will have exited from the
+ * scanning loop immediately, and ub will be a valid uberblock. */
+ blkid_probe_sprintf_version(pr, "%" PRIu64, swab_endian ?
+ swab64(ub->ub_version) : ub->ub_version);
+
+ zfs_extract_guid_name(pr, offset);
+
+ if (blkid_probe_set_magic(pr, offset,
+ sizeof(ub->ub_magic),
+ (unsigned char *) &ub->ub_magic))
+ return -1;
+
+ return 0;
+}
+
+const struct blkid_idinfo zfs_idinfo =
+{
+ .name = "zfs_member",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_zfs,
+ .minsz = 64 * 1024 * 1024,
+ .magics = BLKID_NONE_MAGIC
+};
+