summaryrefslogtreecommitdiff
path: root/extras/volume_id/lib
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@suse.de>2006-03-27 18:05:17 +0200
committerKay Sievers <kay.sievers@suse.de>2006-03-27 18:05:17 +0200
commit83cc6ab4760817509f1ed1ee429669e563f82caf (patch)
tree1d9ef7edcae7678f356c19e0b85c09f094576454 /extras/volume_id/lib
parentb5e694267142042228a6cac99ecad6c4b4ef8759 (diff)
volume_id: rename subdirectory
Diffstat (limited to 'extras/volume_id/lib')
-rw-r--r--extras/volume_id/lib/Makefile124
-rw-r--r--extras/volume_id/lib/cramfs.c64
-rw-r--r--extras/volume_id/lib/ext.c115
-rw-r--r--extras/volume_id/lib/fat.c349
-rw-r--r--extras/volume_id/lib/hfs.c297
-rw-r--r--extras/volume_id/lib/highpoint.c96
-rw-r--r--extras/volume_id/lib/hpfs.c56
-rw-r--r--extras/volume_id/lib/iso9660.c124
-rw-r--r--extras/volume_id/lib/isw_raid.c66
-rw-r--r--extras/volume_id/lib/jfs.c65
-rw-r--r--extras/volume_id/lib/libvolume_id.h111
-rw-r--r--extras/volume_id/lib/linux_raid.c87
-rw-r--r--extras/volume_id/lib/linux_swap.c76
-rw-r--r--extras/volume_id/lib/lsi_raid.c60
-rw-r--r--extras/volume_id/lib/luks.c82
-rw-r--r--extras/volume_id/lib/lvm.c97
-rw-r--r--extras/volume_id/lib/minix.c84
-rw-r--r--extras/volume_id/lib/ntfs.c194
-rw-r--r--extras/volume_id/lib/nvidia_raid.c64
-rw-r--r--extras/volume_id/lib/ocfs.c192
-rw-r--r--extras/volume_id/lib/promise_raid.c70
-rw-r--r--extras/volume_id/lib/reiserfs.c118
-rw-r--r--extras/volume_id/lib/romfs.c60
-rw-r--r--extras/volume_id/lib/silicon_raid.c77
-rw-r--r--extras/volume_id/lib/squashfs.c52
-rw-r--r--extras/volume_id/lib/sysv.c133
-rw-r--r--extras/volume_id/lib/udf.c178
-rw-r--r--extras/volume_id/lib/ufs.c210
-rw-r--r--extras/volume_id/lib/util.c267
-rw-r--r--extras/volume_id/lib/util.h84
-rw-r--r--extras/volume_id/lib/via_raid.c75
-rw-r--r--extras/volume_id/lib/volume_id.c231
-rw-r--r--extras/volume_id/lib/vxfs.c54
-rw-r--r--extras/volume_id/lib/xfs.c65
34 files changed, 4077 insertions, 0 deletions
diff --git a/extras/volume_id/lib/Makefile b/extras/volume_id/lib/Makefile
new file mode 100644
index 0000000000..6a12f0e67a
--- /dev/null
+++ b/extras/volume_id/lib/Makefile
@@ -0,0 +1,124 @@
+# libvolume_id - read filesystem label/uuid
+#
+# Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
+#
+# Released under the GNU General Public License, version 2.
+#
+includedir = ${prefix}/usr/include
+libdir = ${prefix}/lib
+usrlibdir = ${prefix}/usr/lib
+
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_LIB = ${INSTALL} -m 755
+
+SHLIB_CUR = 0
+SHLIB_REV = 61
+SHLIB_AGE = 0
+SHLIB = libvolume_id.so.$(SHLIB_CUR).$(SHLIB_REV).$(SHLIB_AGE)
+
+OBJS= \
+ ext.o \
+ fat.o \
+ hfs.o \
+ highpoint.o \
+ isw_raid.o \
+ lsi_raid.o \
+ via_raid.o \
+ silicon_raid.o \
+ nvidia_raid.o \
+ promise_raid.o \
+ iso9660.o \
+ jfs.o \
+ linux_raid.o \
+ linux_swap.o \
+ lvm.o \
+ ntfs.o \
+ reiserfs.o \
+ udf.o \
+ ufs.o \
+ xfs.o \
+ cramfs.o \
+ hpfs.o \
+ romfs.o \
+ sysv.o \
+ minix.o \
+ luks.o \
+ ocfs.o \
+ vxfs.o \
+ squashfs.o \
+ volume_id.o \
+ util.o
+
+HEADERS= \
+ libvolume_id.h \
+ util.h
+
+AR = $(CROSS)ar
+RANLIB = $(CROSS)ranlib
+
+all: libvolume_id.a $(SHLIB) libvolume_id.pc
+.PHONY: all
+.DEFAULT: all
+
+%.o: %.c
+ $(E) " CC " $@
+ $(Q) $(CC) -c $(CFLAGS) $< -o $@
+
+.shlib:
+ $(Q) mkdir .shlib
+
+.shlib/%.o: %.c
+ $(E) " CC " $@
+ $(Q) $(CC) -c $(CFLAGS) -fPIC $< -o $@
+
+libvolume_id.a: $(HEADERS) $(OBJS)
+ $(Q) rm -f $@
+ $(E) " AR " $@
+ $(Q) $(AR) cq $@ $(OBJS)
+ $(E) " RANLIB " $@
+ $(Q) $(RANLIB) $@
+
+$(SHLIB): $(HEADERS) .shlib $(addprefix .shlib/,$(OBJS))
+ $(E) " CC " $@
+ $(Q) $(CC) -shared $(CFLAGS) -o $@ -Wl,-soname,libvolume_id.so.$(SHLIB_CUR) $(addprefix .shlib/,$(OBJS))
+ $(Q) ln -sf $@ libvolume_id.so.$(SHLIB_CUR)
+ $(Q) ln -sf $@ libvolume_id.so
+
+libvolume_id.pc:
+ $(E) " GENPC " $@
+ $(Q) echo "prefix=${prefix}" > $@
+ $(Q) echo "libdir=${libdir}" >> $@
+ $(Q) echo "includedir=${includedir}" >> $@
+ $(Q) echo "" >> $@
+ $(Q) echo "Name: libvolume_id" >> $@
+ $(Q) echo "Description: Filesystem label and uuid access" >> $@
+ $(Q) echo "Version: $(SHLIB_CUR).$(SHLIB_REV).$(SHLIB_AGE)" >> $@
+ $(Q) echo "Libs: -L\$${libdir} -lvolume_id" >> $@
+ $(Q) echo "Cflags: -I\$${includedir}" >> $@
+
+install: all
+ $(INSTALL_DATA) -D libvolume_id.h $(DESTDIR)$(includedir)/libvolume_id.h
+ $(INSTALL_LIB) -D libvolume_id.a $(DESTDIR)$(usrlibdir)/libvolume_id.a
+ $(INSTALL_LIB) -D $(SHLIB) $(DESTDIR)$(libdir)/$(SHLIB)
+ ln -sf $(DESTDIR)$(libdir)/$(SHLIB) $(DESTDIR)$(libdir)/libvolume_id.so.$(SHLIB_CUR)
+ ln -sf $(DESTDIR)$(libdir)/$(SHLIB) $(DESTDIR)$(usrlibdir)/libvolume_id.so
+ $(INSTALL_DATA) -D libvolume_id.pc $(DESTDIR)$(usrlibdir)/pkgconfig/libvolume_id.pc
+.PHONY: install
+
+uninstall:
+ rm -f $(DESTDIR)$(includedir)/libvolume_id.h
+ rm -f $(DESTDIR)$(usrlibdir)/libvolume_id.a
+ rm -f $(DESTDIR)$(libdir)/$(SHLIB)
+ rm -f $(DESTDIR)$(libdir)/libvolume_id.so.$(SHLIB_CUR)
+ rm -f $(DESTDIR)$(libdir)/libvolume_id.so
+.PHONY: uninstall
+
+clean:
+ $(E) " CLEAN "
+ $(Q) rm -f libvolume_id.a $(OBJS)
+ $(Q) rm -f $(SHLIB) libvolume_id.so.$(SHLIB_CUR) libvolume_id.so
+ $(Q) rm -rf .shlib
+ $(Q) rm -f libvolume_id.pc
+.PHONY: clean
+
diff --git a/extras/volume_id/lib/cramfs.c b/extras/volume_id/lib/cramfs.c
new file mode 100644
index 0000000000..beb34d5bc0
--- /dev/null
+++ b/extras/volume_id/lib/cramfs.c
@@ -0,0 +1,64 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.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;
+ } PACKED info;
+ uint8_t name[16];
+} PACKED;
+
+int volume_id_probe_cramfs(struct volume_id *id, uint64_t off)
+{
+ struct cramfs_super *cs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ cs = (struct cramfs_super *) volume_id_get_buffer(id, off, 0x200);
+ if (cs == NULL)
+ return -1;
+
+ if (memcmp(cs->magic, "\x45\x3d\xcd\x28", 4) == 0 || memcmp(cs->magic, "\x28\xcd\x3d\x45", 4) == 0) {
+ volume_id_set_label_raw(id, cs->name, 16);
+ volume_id_set_label_string(id, cs->name, 16);
+
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "cramfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/extras/volume_id/lib/ext.c b/extras/volume_id/lib/ext.c
new file mode 100644
index 0000000000..51c0011218
--- /dev/null
+++ b/extras/volume_id/lib/ext.c
@@ -0,0 +1,115 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.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_log_frag_size;
+ uint32_t s_blocks_per_group;
+ uint32_t s_frags_per_group;
+ uint32_t s_inodes_per_group;
+ uint32_t s_mtime;
+ uint32_t s_wtime;
+ uint16_t s_mnt_count;
+ uint16_t s_max_mnt_count;
+ uint16_t s_magic;
+ 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;
+ uint8_t s_uuid[16];
+ uint8_t s_volume_name[16];
+} PACKED;
+
+#define EXT_SUPER_MAGIC 0xEF53
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
+#define EXT_SUPERBLOCK_OFFSET 0x400
+
+#define EXT3_MIN_BLOCK_SIZE 0x400
+#define EXT3_MAX_BLOCK_SIZE 0x1000
+
+int volume_id_probe_ext(struct volume_id *id, uint64_t off)
+{
+ struct ext2_super_block *es;
+ size_t bsize;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ es = (struct ext2_super_block *) volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
+ if (es == NULL)
+ return -1;
+
+ if (es->s_magic != cpu_to_le16(EXT_SUPER_MAGIC))
+ return -1;
+
+ bsize = 0x400 << le32_to_cpu(es->s_log_block_size);
+ dbg("ext blocksize 0x%zx", bsize);
+ if (bsize < EXT3_MIN_BLOCK_SIZE || bsize > EXT3_MAX_BLOCK_SIZE) {
+ dbg("invalid ext blocksize");
+ return -1;
+ }
+
+ volume_id_set_label_raw(id, es->s_volume_name, 16);
+ volume_id_set_label_string(id, es->s_volume_name, 16);
+ volume_id_set_uuid(id, es->s_uuid, UUID_DCE);
+ snprintf(id->type_version, sizeof(id->type_version)-1,
+ "%u.%u", es->s_rev_level, es->s_minor_rev_level);
+
+ /* check for external journal device */
+ if ((le32_to_cpu(es->s_feature_incompat) & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) != 0) {
+ volume_id_set_usage(id, VOLUME_ID_OTHER);
+ id->type = "jbd";
+ return 0;
+ }
+
+ /* check for ext2 / ext3 */
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ if ((le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0)
+ id->type = "ext3";
+ else
+ id->type = "ext2";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/fat.c b/extras/volume_id/lib/fat.c
new file mode 100644
index 0000000000..4840a2a23c
--- /dev/null
+++ b/extras/volume_id/lib/fat.c
@@ -0,0 +1,349 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+#define FAT12_MAX 0xff5
+#define FAT16_MAX 0xfff5
+#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
+
+struct vfat_super_block {
+ uint8_t boot_jump[3];
+ uint8_t sysid[8];
+ uint16_t sector_size;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved;
+ uint8_t fats;
+ uint16_t dir_entries;
+ uint16_t sectors;
+ uint8_t media;
+ uint16_t fat_length;
+ uint16_t secs_track;
+ uint16_t heads;
+ uint32_t hidden;
+ uint32_t total_sect;
+ union {
+ struct fat_super_block {
+ uint8_t unknown[3];
+ uint8_t serno[4];
+ uint8_t label[11];
+ uint8_t magic[8];
+ uint8_t dummy2[192];
+ uint8_t pmagic[2];
+ } PACKED fat;
+ struct fat32_super_block {
+ uint32_t fat32_length;
+ uint16_t flags;
+ uint8_t version[2];
+ uint32_t root_cluster;
+ uint16_t insfo_sector;
+ uint16_t backup_boot;
+ uint16_t reserved2[6];
+ uint8_t unknown[3];
+ uint8_t serno[4];
+ uint8_t label[11];
+ uint8_t magic[8];
+ uint8_t dummy2[164];
+ uint8_t pmagic[2];
+ } PACKED fat32;
+ } PACKED type;
+} 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;
+} PACKED;
+
+static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ /* end marker */
+ if (dir[i].name[0] == 0x00) {
+ dbg("end of dir");
+ break;
+ }
+
+ /* empty entry */
+ if (dir[i].name[0] == FAT_ENTRY_FREE)
+ continue;
+
+ /* long name */
+ if ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
+ continue;
+
+ if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
+ /* labels do not have file data */
+ if (dir[i].cluster_high != 0 || dir[i].cluster_low != 0)
+ continue;
+
+ dbg("found ATTR_VOLUME_ID id in root dir");
+ return dir[i].name;
+ }
+
+ dbg("skip dir entry");
+ }
+
+ return NULL;
+}
+
+int volume_id_probe_vfat(struct volume_id *id, uint64_t off)
+{
+ struct vfat_super_block *vs;
+ struct vfat_dir_entry *dir;
+ uint16_t sector_size;
+ uint16_t dir_entries;
+ uint32_t sect_count;
+ uint16_t reserved;
+ uint32_t fat_size;
+ uint32_t root_cluster;
+ uint32_t dir_size;
+ uint32_t cluster_count;
+ uint16_t fat_length;
+ uint32_t fat32_length;
+ uint64_t root_start;
+ uint32_t start_data_sect;
+ uint16_t root_dir_entries;
+ uint8_t *buf;
+ uint32_t buf_size;
+ uint8_t *label = NULL;
+ uint32_t next;
+ int maxloop;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
+ if (vs == NULL)
+ return -1;
+
+ /* believe only that's fat, don't trust the version
+ * the cluster_count will tell us
+ */
+ if (memcmp(vs->sysid, "NTFS", 4) == 0)
+ return -1;
+
+ if (memcmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
+ goto magic;
+
+ if (memcmp(vs->type.fat32.magic, "FAT32 ", 8) == 0)
+ goto magic;
+
+ if (memcmp(vs->type.fat.magic, "FAT16 ", 8) == 0)
+ goto magic;
+
+ if (memcmp(vs->type.fat.magic, "MSDOS", 5) == 0)
+ goto magic;
+
+ if (memcmp(vs->type.fat.magic, "FAT12 ", 8) == 0)
+ goto magic;
+
+ /* some old floppies don't have a magic, so we expect the boot code to match */
+
+ /* boot jump address check */
+ if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
+ vs->boot_jump[0] != 0xe9)
+ return -1;
+
+magic:
+ /* reserverd sector count */
+ if (!vs->reserved)
+ return -1;
+
+ /* fat count*/
+ if (!vs->fats)
+ return -1;
+
+ /* media check */
+ if (vs->media < 0xf8 && vs->media != 0xf0)
+ return -1;
+
+ /* cluster size check*/
+ if (vs->sectors_per_cluster == 0 ||
+ (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
+ return -1;
+
+ /* sector size check */
+ sector_size = le16_to_cpu(vs->sector_size);
+ if (sector_size != 0x200 && sector_size != 0x400 &&
+ sector_size != 0x800 && sector_size != 0x1000)
+ return -1;
+
+ dbg("sector_size 0x%x", sector_size);
+ dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
+
+ dir_entries = le16_to_cpu(vs->dir_entries);
+ reserved = le16_to_cpu(vs->reserved);
+ dbg("reserved 0x%x", reserved);
+
+ sect_count = le16_to_cpu(vs->sectors);
+ if (sect_count == 0)
+ sect_count = le32_to_cpu(vs->total_sect);
+ dbg("sect_count 0x%x", sect_count);
+
+ fat_length = le16_to_cpu(vs->fat_length);
+ dbg("fat_length 0x%x", fat_length);
+ fat32_length = le32_to_cpu(vs->type.fat32.fat32_length);
+ dbg("fat32_length 0x%x", fat32_length);
+
+ if (fat_length)
+ fat_size = fat_length * vs->fats;
+ else if (fat32_length)
+ fat_size = fat32_length * vs->fats;
+ else
+ return -1;
+ dbg("fat_size 0x%x", fat_size);
+
+ dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
+ (sector_size-1)) / sector_size;
+ dbg("dir_size 0x%x", dir_size);
+
+ cluster_count = sect_count - (reserved + fat_size + dir_size);
+ cluster_count /= vs->sectors_per_cluster;
+ dbg("cluster_count 0x%x", cluster_count);
+
+ /* must be FAT32 */
+ if (!fat_length && fat32_length)
+ goto fat32;
+
+ /* cluster_count tells us the format */
+ if (cluster_count < FAT12_MAX)
+ strcpy(id->type_version, "FAT12");
+ else if (cluster_count < FAT16_MAX)
+ strcpy(id->type_version, "FAT16");
+ else
+ goto fat32;
+
+ /* the label may be an attribute in the root directory */
+ root_start = (reserved + fat_size) * sector_size;
+ dbg("root dir start 0x%llx", (unsigned long long) root_start);
+ root_dir_entries = le16_to_cpu(vs->dir_entries);
+ dbg("expected entries 0x%x", root_dir_entries);
+
+ buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
+ buf = volume_id_get_buffer(id, off + root_start, buf_size);
+ if (buf == NULL)
+ goto found;
+
+ dir = (struct vfat_dir_entry*) buf;
+
+ label = get_attr_volume_id(dir, root_dir_entries);
+
+ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
+ if (vs == NULL)
+ return -1;
+
+ if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
+ volume_id_set_label_raw(id, label, 11);
+ volume_id_set_label_string(id, label, 11);
+ } else if (memcmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
+ volume_id_set_label_raw(id, vs->type.fat.label, 11);
+ volume_id_set_label_string(id, vs->type.fat.label, 11);
+ }
+ volume_id_set_uuid(id, vs->type.fat.serno, UUID_DOS);
+ goto found;
+
+fat32:
+ strcpy(id->type_version, "FAT32");
+
+ /* FAT32 root dir is a cluster chain like any other directory */
+ buf_size = vs->sectors_per_cluster * sector_size;
+ root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
+ dbg("root dir cluster %u", root_cluster);
+ start_data_sect = reserved + fat_size;
+
+ next = root_cluster;
+ maxloop = 100;
+ while (--maxloop) {
+ uint32_t next_sect_off;
+ uint64_t next_off;
+ uint64_t fat_entry_off;
+ int count;
+
+ dbg("next cluster %u", next);
+ next_sect_off = (next - 2) * vs->sectors_per_cluster;
+ next_off = (start_data_sect + next_sect_off) * sector_size;
+ dbg("cluster offset 0x%llx", (unsigned long long) next_off);
+
+ /* get cluster */
+ buf = volume_id_get_buffer(id, off + next_off, buf_size);
+ if (buf == NULL)
+ goto found;
+
+ dir = (struct vfat_dir_entry*) buf;
+ count = buf_size / sizeof(struct vfat_dir_entry);
+ dbg("expected entries 0x%x", count);
+
+ label = get_attr_volume_id(dir, count);
+ if (label)
+ break;
+
+ /* get FAT entry */
+ fat_entry_off = (reserved * sector_size) + (next * sizeof(uint32_t));
+ buf = volume_id_get_buffer(id, off + fat_entry_off, buf_size);
+ if (buf == NULL)
+ goto found;
+
+ /* set next cluster */
+ next = le32_to_cpu(*((uint32_t *) buf) & 0x0fffffff);
+ if (next == 0)
+ break;
+ }
+ if (maxloop == 0)
+ dbg("reached maximum follow count of root cluster chain, give up");
+
+ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
+ if (vs == NULL)
+ return -1;
+
+ if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
+ volume_id_set_label_raw(id, label, 11);
+ volume_id_set_label_string(id, label, 11);
+ } else if (memcmp(vs->type.fat32.label, "NO NAME ", 11) != 0) {
+ volume_id_set_label_raw(id, vs->type.fat32.label, 11);
+ volume_id_set_label_string(id, vs->type.fat32.label, 11);
+ }
+ volume_id_set_uuid(id, vs->type.fat32.serno, UUID_DOS);
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "vfat";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/hfs.c b/extras/volume_id/lib/hfs.c
new file mode 100644
index 0000000000..a6e378dd28
--- /dev/null
+++ b/extras/volume_id/lib/hfs.c
@@ -0,0 +1,297 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+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];
+} 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;
+} PACKED *hfs;
+
+struct hfsplus_bnode_descriptor {
+ uint32_t next;
+ uint32_t prev;
+ uint8_t type;
+ uint8_t height;
+ uint16_t num_recs;
+ uint16_t reserved;
+} 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;
+} PACKED;
+
+struct hfsplus_catalog_key {
+ uint16_t key_len;
+ uint32_t parent_id;
+ uint16_t unicode_len;
+ uint8_t unicode[255 * 2];
+} PACKED;
+
+struct hfsplus_extent {
+ uint32_t start_block;
+ uint32_t block_count;
+} 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];
+} 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;
+} PACKED *hfsplus;
+
+#define HFS_SUPERBLOCK_OFFSET 0x400
+#define HFS_NODE_LEAF 0xff
+#define HFSPLUS_POR_CNID 1
+
+int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off)
+{
+ unsigned int blocksize;
+ unsigned int cat_block;
+ unsigned int ext_block_start;
+ unsigned int ext_block_count;
+ int ext;
+ unsigned int leaf_node_head;
+ unsigned int leaf_node_count;
+ unsigned int leaf_node_size;
+ unsigned int leaf_block;
+ uint64_t leaf_off;
+ unsigned int alloc_block_size;
+ unsigned int alloc_first_block;
+ unsigned int embed_first_block;
+ unsigned int record_count;
+ struct hfsplus_bnode_descriptor *descr;
+ struct hfsplus_bheader_record *bnode;
+ struct hfsplus_catalog_key *key;
+ unsigned int label_len;
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+ const uint8_t *buf;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ hfs = (struct hfs_mdb *) buf;
+ if (memcmp(hfs->signature, "BD", 2) != 0)
+ goto checkplus;
+
+ /* it may be just a hfs wrapper for hfs+ */
+ if (memcmp(hfs->embed_sig, "H+", 2) == 0) {
+ alloc_block_size = be32_to_cpu(hfs->al_blk_size);
+ dbg("alloc_block_size 0x%x", alloc_block_size);
+
+ alloc_first_block = be16_to_cpu(hfs->al_bl_st);
+ dbg("alloc_first_block 0x%x", alloc_first_block);
+
+ embed_first_block = be16_to_cpu(hfs->embed_startblock);
+ dbg("embed_first_block 0x%x", embed_first_block);
+
+ off += (alloc_first_block * 512) +
+ (embed_first_block * alloc_block_size);
+ dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+ goto checkplus;
+ }
+
+ if (hfs->label_len > 0 && hfs->label_len < 28) {
+ volume_id_set_label_raw(id, hfs->label, hfs->label_len);
+ volume_id_set_label_string(id, hfs->label, hfs->label_len) ;
+ }
+
+ volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS);
+
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "hfs";
+
+ return 0;
+
+checkplus:
+ hfsplus = (struct hfsplus_vol_header *) buf;
+ if (memcmp(hfsplus->signature, "H+", 2) == 0)
+ goto hfsplus;
+ if (memcmp(hfsplus->signature, "HX", 2) == 0)
+ goto hfsplus;
+ return -1;
+
+hfsplus:
+ volume_id_set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
+
+ blocksize = be32_to_cpu(hfsplus->blocksize);
+ dbg("blocksize %u", blocksize);
+
+ memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+ cat_block = be32_to_cpu(extents[0].start_block);
+ dbg("catalog start block 0x%x", cat_block);
+
+ buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000);
+ if (buf == NULL)
+ goto found;
+
+ bnode = (struct hfsplus_bheader_record *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ leaf_node_head = be32_to_cpu(bnode->leaf_head);
+ dbg("catalog leaf node 0x%x", leaf_node_head);
+
+ leaf_node_size = be16_to_cpu(bnode->node_size);
+ dbg("leaf node size 0x%x", leaf_node_size);
+
+ leaf_node_count = be32_to_cpu(bnode->leaf_count);
+ dbg("leaf node count 0x%x", leaf_node_count);
+ if (leaf_node_count == 0)
+ goto found;
+
+ 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);
+ dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
+
+ if (ext_block_count == 0)
+ goto found;
+
+ /* this is our extent */
+ if (leaf_block < ext_block_count)
+ break;
+
+ leaf_block -= ext_block_count;
+ }
+ if (ext == HFSPLUS_EXTENT_COUNT)
+ goto found;
+ dbg("found block in extent %i", ext);
+
+ leaf_off = (ext_block_start + leaf_block) * blocksize;
+
+ buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size);
+ if (buf == NULL)
+ goto found;
+
+ descr = (struct hfsplus_bnode_descriptor *) buf;
+ dbg("descriptor type 0x%x", descr->type);
+
+ record_count = be16_to_cpu(descr->num_recs);
+ dbg("number of records %u", record_count);
+ if (record_count == 0)
+ goto found;
+
+ if (descr->type != HFS_NODE_LEAF)
+ goto found;
+
+ key = (struct hfsplus_catalog_key *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
+ if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
+ goto found;
+
+ label_len = be16_to_cpu(key->unicode_len) * 2;
+ dbg("label unicode16 len %i", label_len);
+ volume_id_set_label_raw(id, key->unicode, label_len);
+ volume_id_set_label_unicode16(id, key->unicode, BE, label_len);
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "hfsplus";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/highpoint.c b/extras/volume_id/lib/highpoint.c
new file mode 100644
index 0000000000..deba540ad5
--- /dev/null
+++ b/extras/volume_id/lib/highpoint.c
@@ -0,0 +1,96 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct hpt37x_meta {
+ uint8_t filler1[32];
+ uint32_t magic;
+} PACKED;
+
+struct hpt45x_meta {
+ uint32_t magic;
+} PACKED;
+
+#define HPT37X_CONFIG_OFF 0x1200
+#define HPT37X_MAGIC_OK 0x5a7816f0
+#define HPT37X_MAGIC_BAD 0x5a7816fd
+
+#define HPT45X_MAGIC_OK 0x5a7816f3
+#define HPT45X_MAGIC_BAD 0x5a7816fd
+
+
+int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ struct hpt37x_meta *hpt;
+ uint32_t magic;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ hpt = (struct hpt37x_meta *) buf;
+ magic = le32_to_cpu(hpt->magic);
+ if (magic != HPT37X_MAGIC_OK && magic != HPT37X_MAGIC_BAD)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ id->type = "highpoint_raid_member";
+
+ return 0;
+}
+
+int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ struct hpt45x_meta *hpt;
+ uint64_t meta_off;
+ uint32_t magic;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-11) * 0x200;
+ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ hpt = (struct hpt45x_meta *) buf;
+ magic = le32_to_cpu(hpt->magic);
+ if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ id->type = "highpoint_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/hpfs.c b/extras/volume_id/lib/hpfs.c
new file mode 100644
index 0000000000..3e9589fcca
--- /dev/null
+++ b/extras/volume_id/lib/hpfs.c
@@ -0,0 +1,56 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct hpfs_super
+{
+ uint8_t magic[4];
+ uint8_t version;
+} PACKED;
+
+#define HPFS_SUPERBLOCK_OFFSET 0x2000
+
+int volume_id_probe_hpfs(struct volume_id *id, uint64_t off)
+{
+ struct hpfs_super *hs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ hs = (struct hpfs_super *) volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x200);
+ if (hs == NULL)
+ return -1;
+
+ if (memcmp(hs->magic, "\x49\xe8\x95\xf9", 4) == 0) {
+ sprintf(id->type_version, "%u", hs->version);
+
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "hpfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/extras/volume_id/lib/iso9660.c b/extras/volume_id/lib/iso9660.c
new file mode 100644
index 0000000000..7b78a7e992
--- /dev/null
+++ b/extras/volume_id/lib/iso9660.c
@@ -0,0 +1,124 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+#define ISO_SUPERBLOCK_OFFSET 0x8000
+#define ISO_SECTOR_SIZE 0x800
+#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
+#define ISO_VD_PRIMARY 0x1
+#define ISO_VD_SUPPLEMENTARY 0x2
+#define ISO_VD_END 0xff
+#define ISO_VD_MAX 16
+
+struct iso_volume_descriptor {
+ uint8_t vd_type;
+ uint8_t vd_id[5];
+ uint8_t vd_version;
+ uint8_t flags;
+ uint8_t system_id[32];
+ uint8_t volume_id[32];
+ uint8_t unused[8];
+ uint8_t space_size[8];
+ uint8_t escape_sequences[8];
+} PACKED;
+
+struct high_sierra_volume_descriptor {
+ uint8_t foo[8];
+ uint8_t type;
+ uint8_t id[4];
+ uint8_t version;
+} PACKED;
+
+int volume_id_probe_iso9660(struct volume_id *id, uint64_t off)
+{
+ uint8_t *buf;
+ struct iso_volume_descriptor *is;
+ struct high_sierra_volume_descriptor *hs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ is = (struct iso_volume_descriptor *) buf;
+
+ if (memcmp(is->vd_id, "CD001", 5) == 0) {
+ int vd_offset;
+ int i;
+
+ dbg("read label from PVD");
+ volume_id_set_label_raw(id, is->volume_id, 32);
+ volume_id_set_label_string(id, is->volume_id, 32);
+
+ dbg("looking for SVDs");
+ vd_offset = ISO_VD_OFFSET;
+ for (i = 0; i < ISO_VD_MAX; i++) {
+ uint8_t svd_label[64];
+
+ is = (struct iso_volume_descriptor *) volume_id_get_buffer(id, off + vd_offset, 0x200);
+ if (is == NULL || is->vd_type == ISO_VD_END)
+ break;
+ if (is->vd_type != ISO_VD_SUPPLEMENTARY)
+ continue;
+
+ dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset));
+ if (memcmp(is->escape_sequences, "%/@", 3) == 0||
+ memcmp(is->escape_sequences, "%/C", 3) == 0||
+ memcmp(is->escape_sequences, "%/E", 3) == 0) {
+ dbg("Joliet extension found");
+ volume_id_set_unicode16((char *)svd_label, sizeof(svd_label), is->volume_id, BE, 32);
+ if (memcmp(id->label, svd_label, 16) == 0) {
+ dbg("SVD label is identical, use the possibly longer PVD one");
+ break;
+ }
+
+ volume_id_set_label_raw(id, is->volume_id, 32);
+ volume_id_set_label_string(id, svd_label, 32);
+ strcpy(id->type_version, "Joliet Extension");
+ goto found;
+ }
+ vd_offset += ISO_SECTOR_SIZE;
+ }
+ goto found;
+ }
+
+ hs = (struct high_sierra_volume_descriptor *) buf;
+
+ if (memcmp(hs->id, "CDROM", 5) == 0) {
+ strcpy(id->type_version, "High Sierra");
+ goto found;
+ }
+
+ return -1;
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "iso9660";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/isw_raid.c b/extras/volume_id/lib/isw_raid.c
new file mode 100644
index 0000000000..6465a31bf5
--- /dev/null
+++ b/extras/volume_id/lib/isw_raid.c
@@ -0,0 +1,66 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct isw_meta {
+ uint8_t sig[32];
+ uint32_t check_sum;
+ uint32_t mpb_size;
+ uint32_t family_num;
+ uint32_t generation_num;
+} PACKED;
+
+#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. "
+
+
+int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ uint64_t meta_off;
+ struct isw_meta *isw;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-2) * 0x200;
+ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ isw = (struct isw_meta *) buf;
+ if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ memcpy(id->type_version, &isw->sig[sizeof(ISW_SIGNATURE)-1], 6);
+ id->type = "isw_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/jfs.c b/extras/volume_id/lib/jfs.c
new file mode 100644
index 0000000000..b230fb258c
--- /dev/null
+++ b/extras/volume_id/lib/jfs.c
@@ -0,0 +1,65 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct jfs_super_block {
+ uint8_t magic[4];
+ uint32_t version;
+ uint64_t size;
+ uint32_t bsize;
+ uint32_t dummy1;
+ uint32_t pbsize;
+ uint32_t dummy2[27];
+ uint8_t uuid[16];
+ uint8_t label[16];
+ uint8_t loguuid[16];
+} PACKED;
+
+#define JFS_SUPERBLOCK_OFFSET 0x8000
+
+int volume_id_probe_jfs(struct volume_id *id, uint64_t off)
+{
+ struct jfs_super_block *js;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ js = (struct jfs_super_block *) volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
+ if (js == NULL)
+ return -1;
+
+ if (memcmp(js->magic, "JFS1", 4) != 0)
+ return -1;
+
+ volume_id_set_label_raw(id, js->label, 16);
+ volume_id_set_label_string(id, js->label, 16);
+ volume_id_set_uuid(id, js->uuid, UUID_DCE);
+
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "jfs";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/libvolume_id.h b/extras/volume_id/lib/libvolume_id.h
new file mode 100644
index 0000000000..7faf8d8af3
--- /dev/null
+++ b/extras/volume_id/lib/libvolume_id.h
@@ -0,0 +1,111 @@
+/*
+ * volume_id - reads volume label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _LIBVOLUME_ID_H_
+#define _LIBVOLUME_ID_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifndef PACKED
+#define PACKED __attribute__((packed))
+#endif
+
+
+typedef void (*volume_id_log_fn)(int priority, const char *file, int line, const char *format, ...)
+ __attribute__ ((format(printf, 4, 5)));
+
+extern volume_id_log_fn volume_id_log;
+
+#define VOLUME_ID_LABEL_SIZE 64
+#define VOLUME_ID_UUID_SIZE 36
+#define VOLUME_ID_FORMAT_SIZE 32
+#define VOLUME_ID_PATH_MAX 256
+#define VOLUME_ID_PARTITIONS_MAX 256
+
+enum volume_id_usage {
+ VOLUME_ID_UNUSED,
+ VOLUME_ID_UNPROBED,
+ VOLUME_ID_OTHER,
+ VOLUME_ID_FILESYSTEM,
+ VOLUME_ID_RAID,
+ VOLUME_ID_DISKLABEL,
+ VOLUME_ID_CRYPTO,
+};
+
+struct volume_id {
+ uint8_t label_raw[VOLUME_ID_LABEL_SIZE];
+ size_t label_raw_len;
+ char label[VOLUME_ID_LABEL_SIZE+1];
+ uint8_t uuid_raw[VOLUME_ID_UUID_SIZE];
+ size_t uuid_raw_len;
+ char uuid[VOLUME_ID_UUID_SIZE+1];
+ enum volume_id_usage usage_id;
+ char *usage;
+ char *type;
+ char type_version[VOLUME_ID_FORMAT_SIZE];
+
+ int fd;
+ uint8_t *sbbuf;
+ size_t sbbuf_len;
+ uint8_t *seekbuf;
+ uint64_t seekbuf_off;
+ size_t seekbuf_len;
+ int fd_close:1;
+};
+
+extern struct volume_id *volume_id_open_fd(int fd);
+extern struct volume_id *volume_id_open_node(const char *path);
+extern int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern void volume_id_close(struct volume_id *id);
+
+/* filesystems */
+extern int volume_id_probe_cramfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_ext(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_vfat(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_hpfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_iso9660(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_jfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_minix(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_ntfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_romfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_sysv(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_udf(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_ufs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_vxfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_xfs(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_squashfs(struct volume_id *id, uint64_t off);
+
+/* special formats */
+extern int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_luks(struct volume_id *id, uint64_t off);
+
+/* raid */
+extern int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_lvm1(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_lvm2(struct volume_id *id, uint64_t off);
+
+/* bios raid */
+extern int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off);
+extern int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size);
+
+#endif
diff --git a/extras/volume_id/lib/linux_raid.c b/extras/volume_id/lib/linux_raid.c
new file mode 100644
index 0000000000..85e8d8109b
--- /dev/null
+++ b/extras/volume_id/lib/linux_raid.c
@@ -0,0 +1,87 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct mdp_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;
+} PACKED *mdp;
+
+#define MD_RESERVED_BYTES 0x10000
+#define MD_MAGIC 0xa92b4efc
+
+int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ uint64_t sboff;
+ uint8_t uuid[16];
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
+ buf = volume_id_get_buffer(id, off + sboff, 0x800);
+ if (buf == NULL)
+ return -1;
+
+ mdp = (struct mdp_super_block *) buf;
+
+ if (le32_to_cpu(mdp->md_magic) != MD_MAGIC)
+ return -1;
+
+ memcpy(uuid, &mdp->set_uuid0, 4);
+ memcpy(&uuid[4], &mdp->set_uuid1, 12);
+ volume_id_set_uuid(id, uuid, UUID_DCE);
+
+ snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u.%u",
+ le32_to_cpu(mdp->major_version),
+ le32_to_cpu(mdp->minor_version),
+ le32_to_cpu(mdp->patch_version));
+
+ dbg("found raid signature");
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ id->type = "linux_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/linux_swap.c b/extras/volume_id/lib/linux_swap.c
new file mode 100644
index 0000000000..0193648c9e
--- /dev/null
+++ b/extras/volume_id/lib/linux_swap.c
@@ -0,0 +1,76 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct swap_header_v1_2 {
+ uint8_t bootbits[1024];
+ uint32_t version;
+ uint32_t last_page;
+ uint32_t nr_badpages;
+ uint8_t uuid[16];
+ uint8_t volume_name[16];
+} PACKED *sw;
+
+#define LARGEST_PAGESIZE 0x4000
+
+int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ unsigned int page;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ /* the swap signature is at the end of the PAGE_SIZE */
+ for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
+ buf = volume_id_get_buffer(id, off + page-10, 10);
+ if (buf == NULL)
+ return -1;
+
+ if (memcmp(buf, "SWAP-SPACE", 10) == 0) {
+ strcpy(id->type_version, "1");
+ goto found;
+ }
+
+ if (memcmp(buf, "SWAPSPACE2", 10) == 0) {
+ sw = (struct swap_header_v1_2 *) volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2));
+ if (sw == NULL)
+ return -1;
+ strcpy(id->type_version, "2");
+ volume_id_set_label_raw(id, sw->volume_name, 16);
+ volume_id_set_label_string(id, sw->volume_name, 16);
+ volume_id_set_uuid(id, sw->uuid, UUID_DCE);
+ goto found;
+ }
+ }
+ return -1;
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_OTHER);
+ id->type = "swap";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/lsi_raid.c b/extras/volume_id/lib/lsi_raid.c
new file mode 100644
index 0000000000..f1db4a6e50
--- /dev/null
+++ b/extras/volume_id/lib/lsi_raid.c
@@ -0,0 +1,60 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct lsi_meta {
+ uint8_t sig[6];
+} PACKED;
+
+#define LSI_SIGNATURE "$XIDE$"
+
+int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ uint64_t meta_off;
+ struct lsi_meta *lsi;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-1) * 0x200;
+ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ lsi = (struct lsi_meta *) buf;
+ if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ id->type = "lsi_mega_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/luks.c b/extras/volume_id/lib/luks.c
new file mode 100644
index 0000000000..64de85ac21
--- /dev/null
+++ b/extras/volume_id/lib/luks.c
@@ -0,0 +1,82 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 W. Michael Petullo <mike@flyn.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+#define SECTOR_SHIFT 9
+#define SECTOR_SIZE (1 << SECTOR_SHIFT)
+
+#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_NUMKEYS 8
+
+const uint8_t LUKS_MAGIC[] = {'L','U','K','S', 0xba, 0xbe};
+#define LUKS_MAGIC_L 6
+#define LUKS_PHDR_SIZE (sizeof(struct luks_phdr)/SECTOR_SIZE+1)
+#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];
+ struct {
+ uint32_t active;
+ uint32_t passwordIterations;
+ uint8_t passwordSalt[LUKS_SALTSIZE];
+ uint32_t keyMaterialOffset;
+ uint32_t stripes;
+ } keyblock[LUKS_NUMKEYS];
+};
+
+int volume_id_probe_luks(struct volume_id *id, uint64_t off)
+{
+ struct luks_phdr *header;
+
+ header = (struct luks_phdr*) volume_id_get_buffer(id, off, LUKS_PHDR_SIZE);
+ if (header == NULL)
+ return -1;
+
+ if (memcmp(header->magic, LUKS_MAGIC, LUKS_MAGIC_L))
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_CRYPTO);
+ volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING);
+
+ id->type = "crypto_LUKS";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/lvm.c b/extras/volume_id/lib/lvm.c
new file mode 100644
index 0000000000..47d84b0968
--- /dev/null
+++ b/extras/volume_id/lib/lvm.c
@@ -0,0 +1,97 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct lvm1_super_block {
+ uint8_t id[2];
+} PACKED;
+
+struct lvm2_super_block {
+ uint8_t id[8];
+ uint64_t sector_xl;
+ uint32_t crc_xl;
+ uint32_t offset_xl;
+ uint8_t type[8];
+} PACKED;
+
+#define LVM1_SB_OFF 0x400
+#define LVM1_MAGIC "HM"
+
+int volume_id_probe_lvm1(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ struct lvm1_super_block *lvm;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + LVM1_SB_OFF, 0x800);
+ if (buf == NULL)
+ return -1;
+
+ lvm = (struct lvm1_super_block *) buf;
+
+ if (memcmp(lvm->id, LVM1_MAGIC, 2) != 0)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ id->type = "LVM1_member";
+
+ return 0;
+}
+
+#define LVM2_LABEL_ID "LABELONE"
+#define LVM2LABEL_SCAN_SECTORS 4
+
+int volume_id_probe_lvm2(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ unsigned int soff;
+ struct lvm2_super_block *lvm;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
+ if (buf == NULL)
+ return -1;
+
+
+ for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
+ lvm = (struct lvm2_super_block *) &buf[soff];
+
+ if (memcmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
+ goto found;
+ }
+
+ return -1;
+
+found:
+ memcpy(id->type_version, lvm->type, 8);
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ id->type = "LVM2_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/minix.c b/extras/volume_id/lib/minix.c
new file mode 100644
index 0000000000..75e9c3acbd
--- /dev/null
+++ b/extras/volume_id/lib/minix.c
@@ -0,0 +1,84 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct minix_super_block
+{
+ uint16_t s_ninodes;
+ uint16_t s_nzones;
+ uint16_t s_imap_blocks;
+ uint16_t s_zmap_blocks;
+ uint16_t s_firstdatazone;
+ uint16_t s_log_zone_size;
+ uint32_t s_max_size;
+ uint16_t s_magic;
+ uint16_t s_state;
+ uint32_t s_zones;
+} PACKED;
+
+#define MINIX_SUPERBLOCK_OFFSET 0x400
+
+int volume_id_probe_minix(struct volume_id *id, uint64_t off)
+{
+ struct minix_super_block *ms;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ ms = (struct minix_super_block *) volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200);
+ if (ms == NULL)
+ return -1;
+
+ if (le16_to_cpu(ms->s_magic) == 0x137f) {
+ strcpy(id->type_version, "1");
+ goto found;
+ }
+
+ if (le16_to_cpu(ms->s_magic) == 0x1387) {
+ strcpy(id->type_version, "1");
+ goto found;
+ }
+
+ if (le16_to_cpu(ms->s_magic) == 0x2468) {
+ strcpy(id->type_version, "2");
+ goto found;
+ }
+
+ if (le16_to_cpu(ms->s_magic) == 0x2478) {
+ strcpy(id->type_version, "2");
+ goto found;
+ }
+
+ goto exit;
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "minix";
+ return 0;
+
+exit:
+ return -1;
+}
diff --git a/extras/volume_id/lib/ntfs.c b/extras/volume_id/lib/ntfs.c
new file mode 100644
index 0000000000..23c64fc307
--- /dev/null
+++ b/extras/volume_id/lib/ntfs.c
@@ -0,0 +1,194 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct ntfs_super_block {
+ uint8_t jump[3];
+ uint8_t oem_id[8];
+ uint16_t bytes_per_sector;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sectors;
+ uint8_t fats;
+ uint16_t root_entries;
+ uint16_t sectors;
+ uint8_t media_type;
+ uint16_t sectors_per_fat;
+ uint16_t sectors_per_track;
+ uint16_t heads;
+ uint32_t hidden_sectors;
+ uint32_t large_sectors;
+ uint16_t unused[2];
+ uint64_t number_of_sectors;
+ uint64_t mft_cluster_location;
+ uint64_t mft_mirror_cluster_location;
+ int8_t cluster_per_mft_record;
+ uint8_t reserved1[3];
+ int8_t cluster_per_index_record;
+ uint8_t reserved2[3];
+ uint8_t volume_serial[8];
+ uint16_t checksum;
+} PACKED *ns;
+
+struct master_file_table_record {
+ uint8_t magic[4];
+ 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;
+} PACKED *mftr;
+
+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;
+} PACKED *attr;
+
+struct volume_info {
+ uint64_t reserved;
+ uint8_t major_ver;
+ uint8_t minor_ver;
+} PACKED *info;
+
+#define MFT_RECORD_VOLUME 3
+#define MFT_RECORD_ATTR_VOLUME_NAME 0x60
+#define MFT_RECORD_ATTR_VOLUME_INFO 0x70
+#define MFT_RECORD_ATTR_OBJECT_ID 0x40
+#define MFT_RECORD_ATTR_END 0xffffffffu
+
+int volume_id_probe_ntfs(struct volume_id *id, uint64_t off)
+{
+ unsigned int sector_size;
+ unsigned int cluster_size;
+ uint64_t mft_cluster;
+ uint64_t mft_off;
+ unsigned int mft_record_size;
+ unsigned int attr_type;
+ unsigned int attr_off;
+ unsigned int attr_len;
+ unsigned int val_off;
+ unsigned int val_len;
+ const uint8_t *buf;
+ const uint8_t *val;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ ns = (struct ntfs_super_block *) volume_id_get_buffer(id, off, 0x200);
+ if (ns == NULL)
+ return -1;
+
+ if (memcmp(ns->oem_id, "NTFS", 4) != 0)
+ return -1;
+
+ volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS);
+
+ sector_size = le16_to_cpu(ns->bytes_per_sector);
+ cluster_size = ns->sectors_per_cluster * sector_size;
+ mft_cluster = le64_to_cpu(ns->mft_cluster_location);
+ mft_off = mft_cluster * cluster_size;
+
+ if (ns->cluster_per_mft_record < 0)
+ /* size = -log2(mft_record_size); normally 1024 Bytes */
+ mft_record_size = 1 << -ns->cluster_per_mft_record;
+ else
+ mft_record_size = ns->cluster_per_mft_record * cluster_size;
+
+ dbg("sectorsize 0x%x", sector_size);
+ dbg("clustersize 0x%x", cluster_size);
+ dbg("mftcluster %llu", (unsigned long long) mft_cluster);
+ dbg("mftoffset 0x%llx", (unsigned long long) mft_off);
+ dbg("cluster per mft_record %i", ns->cluster_per_mft_record);
+ dbg("mft record size %i", mft_record_size);
+
+ buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
+ mft_record_size);
+ if (buf == NULL)
+ goto found;
+
+ mftr = (struct master_file_table_record*) buf;
+
+ dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
+ if (memcmp(mftr->magic, "FILE", 4) != 0)
+ goto found;
+
+ attr_off = le16_to_cpu(mftr->attrs_offset);
+ dbg("file $Volume's attributes are at offset %i", attr_off);
+
+ while (1) {
+ attr = (struct file_attribute*) &buf[attr_off];
+ attr_type = le32_to_cpu(attr->type);
+ attr_len = le16_to_cpu(attr->len);
+ val_off = le16_to_cpu(attr->value_offset);
+ val_len = le32_to_cpu(attr->value_len);
+ attr_off += attr_len;
+
+ if (attr_len == 0)
+ break;
+
+ if (attr_off >= mft_record_size)
+ break;
+
+ if (attr_type == MFT_RECORD_ATTR_END)
+ break;
+
+ dbg("found attribute type 0x%x, len %i, at offset %i",
+ attr_type, attr_len, attr_off);
+
+ if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
+ dbg("found info, len %i", val_len);
+ info = (struct volume_info*) (((uint8_t *) attr) + val_off);
+ snprintf(id->type_version, sizeof(id->type_version)-1,
+ "%u.%u", info->major_ver, info->minor_ver);
+ }
+
+ if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
+ dbg("found label, len %i", val_len);
+ if (val_len > VOLUME_ID_LABEL_SIZE)
+ val_len = VOLUME_ID_LABEL_SIZE;
+
+ val = ((uint8_t *) attr) + val_off;
+ volume_id_set_label_raw(id, val, val_len);
+ volume_id_set_label_unicode16(id, val, LE, val_len);
+ }
+ }
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "ntfs";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/nvidia_raid.c b/extras/volume_id/lib/nvidia_raid.c
new file mode 100644
index 0000000000..10c1c714f7
--- /dev/null
+++ b/extras/volume_id/lib/nvidia_raid.c
@@ -0,0 +1,64 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct nvidia_meta {
+ uint8_t vendor[8];
+ uint32_t size;
+ uint32_t chksum;
+ uint16_t version;
+} PACKED;
+
+#define NVIDIA_SIGNATURE "NVIDIA"
+
+int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ uint64_t meta_off;
+ struct nvidia_meta *nv;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-2) * 0x200;
+ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ nv = (struct nvidia_meta *) buf;
+ if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ snprintf(id->type_version, sizeof(id->type_version)-1, "%u", le16_to_cpu(nv->version));
+ id->type = "nvidia_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/ocfs.c b/extras/volume_id/lib/ocfs.c
new file mode 100644
index 0000000000..b376ead833
--- /dev/null
+++ b/extras/volume_id/lib/ocfs.c
@@ -0,0 +1,192 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Andre Masella <andre@masella.no-ip.org>
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+
+struct ocfs1_super_block_header {
+ uint32_t minor_version;
+ uint32_t major_version;
+ uint8_t signature[128];
+ uint8_t mount_point[128];
+ uint64_t serial_num;
+ uint64_t device_size;
+ uint64_t start_off;
+ uint64_t bitmap_off;
+ uint64_t publ_off;
+ uint64_t vote_off;
+ uint64_t root_bitmap_off;
+ uint64_t data_start_off;
+ uint64_t root_bitmap_size;
+ uint64_t root_off;
+ uint64_t root_size;
+ uint64_t cluster_size;
+ uint64_t num_nodes;
+ uint64_t num_clusters;
+ uint64_t dir_node_size;
+ uint64_t file_node_size;
+ uint64_t internal_off;
+ uint64_t node_cfg_off;
+ uint64_t node_cfg_size;
+ uint64_t new_cfg_off;
+ uint32_t prot_bits;
+ int32_t excl_mount;
+} PACKED;
+
+struct ocfs1_super_block_label {
+ struct ocfs1_disk_lock {
+ uint32_t curr_master;
+ uint8_t file_lock;
+ uint8_t compat_pad[3];
+ uint64_t last_write_time;
+ uint64_t last_read_time;
+ uint32_t writer_node_num;
+ uint32_t reader_node_num;
+ uint64_t oin_node_map;
+ uint64_t dlock_seq_num;
+ } PACKED disk_lock;
+ uint8_t label[64];
+ uint16_t label_len;
+ uint8_t vol_id[16];
+ uint16_t vol_id_len;
+ uint8_t cluster_name[64];
+ uint16_t cluster_name_len;
+} PACKED;
+
+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];
+} PACKED;
+
+int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ struct ocfs1_super_block_header *osh;
+ struct ocfs1_super_block_label *osl;
+
+ buf = volume_id_get_buffer(id, off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ osh = (struct ocfs1_super_block_header *) buf;
+ if (memcmp(osh->signature, "OracleCFS", 9) != 0)
+ return -1;
+ snprintf(id->type_version, sizeof(id->type_version)-1,
+ "%u.%u", osh->major_version, osh->minor_version);
+
+ dbg("found OracleCFS signature, now reading label");
+ buf = volume_id_get_buffer(id, off + 0x200, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ osl = (struct ocfs1_super_block_label *) buf;
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ if (osl->label_len <= 64) {
+ volume_id_set_label_raw(id, osl->label, 64);
+ volume_id_set_label_string(id, osl->label, 64);
+ }
+ if (osl->vol_id_len == 16)
+ volume_id_set_uuid(id, osl->vol_id, UUID_DCE);
+ id->type = "ocfs";
+ return 0;
+}
+
+#define OCFS2_MAX_BLOCKSIZE 0x1000
+#define OCFS2_SUPER_BLOCK_BLKNO 2
+
+int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ struct ocfs2_super_block *os;
+ size_t blksize;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ for (blksize = 0x200; blksize <= OCFS2_MAX_BLOCKSIZE; blksize <<= 1) {
+ buf = volume_id_get_buffer(id, off + OCFS2_SUPER_BLOCK_BLKNO * blksize, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ os = (struct ocfs2_super_block *) buf;
+ if (memcmp(os->i_signature, "OCFSV2", 6) != 0)
+ continue;
+
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ volume_id_set_label_raw(id, os->s_label, 64);
+ volume_id_set_label_string(id, os->s_label, 64);
+ volume_id_set_uuid(id, os->s_uuid, UUID_DCE);
+ snprintf(id->type_version, sizeof(id->type_version)-1,
+ "%u.%u", os->s_major_rev_level, os->s_minor_rev_level);
+ id->type = "ocfs2";
+ return 0;
+ }
+ return -1;
+}
diff --git a/extras/volume_id/lib/promise_raid.c b/extras/volume_id/lib/promise_raid.c
new file mode 100644
index 0000000000..2a2ce1689e
--- /dev/null
+++ b/extras/volume_id/lib/promise_raid.c
@@ -0,0 +1,70 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct promise_meta {
+ uint8_t sig[24];
+} PACKED;
+
+#define PDC_CONFIG_OFF 0x1200
+#define PDC_SIGNATURE "Promise Technology, Inc."
+
+int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ struct promise_meta *pdc;
+ unsigned int i;
+ static unsigned int sectors[] = {
+ 63, 255, 256, 16, 399, 0
+ };
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x40000)
+ return -1;
+
+ for (i = 0; sectors[i] != 0; i++) {
+ uint64_t meta_off;
+
+ meta_off = ((size / 0x200) - sectors[i]) * 0x200;
+ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ pdc = (struct promise_meta *) buf;
+ if (memcmp(pdc->sig, PDC_SIGNATURE, sizeof(PDC_SIGNATURE)-1) == 0)
+ goto found;
+ }
+ return -1;
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ id->type = "promise_fasttrack_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/reiserfs.c b/extras/volume_id/lib/reiserfs.c
new file mode 100644
index 0000000000..b5706f86e0
--- /dev/null
+++ b/extras/volume_id/lib/reiserfs.c
@@ -0,0 +1,118 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2005 Tobias Klauser <tklauser@access.unizh.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct reiserfs_super_block {
+ uint32_t blocks_count;
+ uint32_t free_blocks;
+ uint32_t root_block;
+ uint32_t journal_block;
+ uint32_t journal_dev;
+ uint32_t orig_journal_size;
+ uint32_t dummy2[5];
+ uint16_t blocksize;
+ uint16_t dummy3[3];
+ uint8_t magic[12];
+ uint32_t dummy4[5];
+ uint8_t uuid[16];
+ uint8_t label[16];
+} PACKED;
+
+struct reiser4_super_block {
+ uint8_t magic[16];
+ uint16_t dummy[2];
+ uint8_t uuid[16];
+ uint8_t label[16];
+ uint64_t dummy2;
+} PACKED;
+
+#define REISERFS1_SUPERBLOCK_OFFSET 0x2000
+#define REISERFS_SUPERBLOCK_OFFSET 0x10000
+
+int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off)
+{
+ struct reiserfs_super_block *rs;
+ struct reiser4_super_block *rs4;
+ uint8_t *buf;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ rs = (struct reiserfs_super_block *) buf;;
+ if (memcmp(rs->magic, "ReIsErFs", 8) == 0) {
+ strcpy(id->type_version, "3.5");
+ id->type = "reiserfs";
+ goto found;
+ }
+ if (memcmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
+ strcpy(id->type_version, "3.6");
+ id->type = "reiserfs";
+ goto found_label;
+ }
+ if (memcmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
+ strcpy(id->type_version, "JR");
+ id->type = "reiserfs";
+ goto found_label;
+ }
+
+ rs4 = (struct reiser4_super_block *) buf;
+ if (memcmp(rs4->magic, "ReIsEr4", 7) == 0) {
+ strcpy(id->type_version, "4");
+ volume_id_set_label_raw(id, rs4->label, 16);
+ volume_id_set_label_string(id, rs4->label, 16);
+ volume_id_set_uuid(id, rs4->uuid, UUID_DCE);
+ id->type = "reiser4";
+ goto found;
+ }
+
+ buf = volume_id_get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ rs = (struct reiserfs_super_block *) buf;
+ if (memcmp(rs->magic, "ReIsErFs", 8) == 0) {
+ strcpy(id->type_version, "3.5");
+ id->type = "reiserfs";
+ goto found;
+ }
+
+ return -1;
+
+found_label:
+ volume_id_set_label_raw(id, rs->label, 16);
+ volume_id_set_label_string(id, rs->label, 16);
+ volume_id_set_uuid(id, rs->uuid, UUID_DCE);
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/romfs.c b/extras/volume_id/lib/romfs.c
new file mode 100644
index 0000000000..8bb2a0018a
--- /dev/null
+++ b/extras/volume_id/lib/romfs.c
@@ -0,0 +1,60 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct romfs_super {
+ uint8_t magic[8];
+ uint32_t size;
+ uint32_t checksum;
+ uint8_t name[0];
+} PACKED;
+
+int volume_id_probe_romfs(struct volume_id *id, uint64_t off)
+{
+ struct romfs_super *rfs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ rfs = (struct romfs_super *) volume_id_get_buffer(id, off, 0x200);
+ if (rfs == NULL)
+ return -1;
+
+ if (memcmp(rfs->magic, "-rom1fs-", 4) == 0) {
+ size_t len = strlen((char *)rfs->name);
+
+ if (len) {
+ volume_id_set_label_raw(id, rfs->name, len);
+ volume_id_set_label_string(id, rfs->name, len);
+ }
+
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "romfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/extras/volume_id/lib/silicon_raid.c b/extras/volume_id/lib/silicon_raid.c
new file mode 100644
index 0000000000..017b023e27
--- /dev/null
+++ b/extras/volume_id/lib/silicon_raid.c
@@ -0,0 +1,77 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct silicon_meta {
+ 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;
+} PACKED;
+
+#define SILICON_MAGIC 0x2F000000
+
+int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ uint64_t meta_off;
+ struct silicon_meta *sil;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-1) * 0x200;
+ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ sil = (struct silicon_meta *) buf;
+ if (le32_to_cpu(sil->magic) != SILICON_MAGIC)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u",
+ le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver));
+ id->type = "silicon_medley_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/squashfs.c b/extras/volume_id/lib/squashfs.c
new file mode 100644
index 0000000000..bdb1f16628
--- /dev/null
+++ b/extras/volume_id/lib/squashfs.c
@@ -0,0 +1,52 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+#define SQUASHFS_MAGIC 0x73717368
+
+struct squashfs_super {
+ uint32_t s_magic;
+} PACKED;
+
+int volume_id_probe_squashfs(struct volume_id *id, uint64_t off)
+{
+ struct squashfs_super *sqs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ sqs = (struct squashfs_super *) volume_id_get_buffer(id, off + 0x200, 0x200);
+ if (sqs == NULL)
+ return -1;
+
+ if (sqs->s_magic == SQUASHFS_MAGIC || sqs->s_magic == bswap_32(SQUASHFS_MAGIC)) {
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "squashfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/extras/volume_id/lib/sysv.c b/extras/volume_id/lib/sysv.c
new file mode 100644
index 0000000000..52349c0623
--- /dev/null
+++ b/extras/volume_id/lib/sysv.c
@@ -0,0 +1,133 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+#define SYSV_NICINOD 100
+#define SYSV_NICFREE 50
+
+struct sysv_super
+{
+ 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;
+} PACKED;
+
+#define XENIX_NICINOD 100
+#define XENIX_NICFREE 100
+
+struct xenix_super {
+ 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;
+} PACKED;
+
+#define SYSV_SUPERBLOCK_BLOCK 0x01
+#define SYSV_MAGIC 0xfd187e20
+#define XENIX_SUPERBLOCK_BLOCK 0x18
+#define XENIX_MAGIC 0x2b5544
+#define SYSV_MAX_BLOCKSIZE 0x800
+
+int volume_id_probe_sysv(struct volume_id *id, uint64_t off)
+{
+ struct sysv_super *vs;
+ struct xenix_super *xs;
+ unsigned int boff;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
+ vs = (struct sysv_super *)
+ volume_id_get_buffer(id, off + (boff * SYSV_SUPERBLOCK_BLOCK), 0x200);
+ if (vs == NULL)
+ return -1;
+
+ if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) {
+ volume_id_set_label_raw(id, vs->s_fname, 6);
+ volume_id_set_label_string(id, vs->s_fname, 6);
+ id->type = "sysv";
+ goto found;
+ }
+ }
+
+ for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
+ xs = (struct xenix_super *)
+ volume_id_get_buffer(id, off + (boff + XENIX_SUPERBLOCK_BLOCK), 0x200);
+ if (xs == NULL)
+ return -1;
+
+ if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) {
+ volume_id_set_label_raw(id, xs->s_fname, 6);
+ volume_id_set_label_string(id, xs->s_fname, 6);
+ id->type = "xenix";
+ goto found;
+ }
+ }
+
+ return -1;
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ return 0;
+}
diff --git a/extras/volume_id/lib/udf.c b/extras/volume_id/lib/udf.c
new file mode 100644
index 0000000000..d7497ec51b
--- /dev/null
+++ b/extras/volume_id/lib/udf.c
@@ -0,0 +1,178 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.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;
+ } PACKED tag;
+ union {
+ struct anchor_descriptor {
+ uint32_t length;
+ uint32_t location;
+ } PACKED anchor;
+ struct primary_descriptor {
+ uint32_t seq_num;
+ uint32_t desc_num;
+ struct dstring {
+ uint8_t clen;
+ uint8_t c[31];
+ } PACKED ident;
+ } PACKED primary;
+ } PACKED type;
+} PACKED;
+
+struct volume_structure_descriptor {
+ uint8_t type;
+ uint8_t id[5];
+ uint8_t version;
+} PACKED;
+
+#define UDF_VSD_OFFSET 0x8000
+
+int volume_id_probe_udf(struct volume_id *id, uint64_t off)
+{
+ struct volume_descriptor *vd;
+ struct volume_structure_descriptor *vsd;
+ unsigned int bs;
+ unsigned int b;
+ unsigned int type;
+ unsigned int count;
+ unsigned int loc;
+ unsigned int clen;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
+ if (vsd == NULL)
+ return -1;
+
+ if (memcmp(vsd->id, "NSR02", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "NSR03", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "BEA01", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "BOOT2", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "CD001", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "CDW02", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "TEA03", 5) == 0)
+ goto blocksize;
+ return -1;
+
+blocksize:
+ /* search the next VSD to get the logical block size of the volume */
+ for (bs = 0x800; bs < 0x8000; bs += 0x800) {
+ vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
+ if (vsd == NULL)
+ return -1;
+ dbg("test for blocksize: 0x%x", bs);
+ 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 *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
+ if (vsd == NULL)
+ return -1;
+
+ dbg("vsd: %c%c%c%c%c",
+ vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
+
+ 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 */
+ vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + (256 * bs), 0x200);
+ if (vd == NULL)
+ return -1;
+
+ type = le16_to_cpu(vd->tag.id);
+ if (type != 2) /* TAG_ID_AVDP */
+ goto found;
+
+ /* get desriptor list address and block count */
+ count = le32_to_cpu(vd->type.anchor.length) / bs;
+ loc = le32_to_cpu(vd->type.anchor.location);
+ dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
+
+ /* pick the primary descriptor from the list */
+ for (b = 0; b < count; b++) {
+ vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200);
+ if (vd == NULL)
+ return -1;
+
+ type = le16_to_cpu(vd->tag.id);
+ dbg("descriptor type %i", type);
+
+ /* check validity */
+ if (type == 0)
+ goto found;
+ if (le32_to_cpu(vd->tag.location) != loc + b)
+ goto found;
+
+ if (type == 1) /* TAG_ID_PVD */
+ goto pvd;
+ }
+ goto found;
+
+pvd:
+ volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32);
+
+ clen = vd->type.primary.ident.clen;
+ dbg("label string charsize=%i bit", clen);
+ if (clen == 8)
+ volume_id_set_label_string(id, vd->type.primary.ident.c, 31);
+ else if (clen == 16)
+ volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "udf";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/ufs.c b/extras/volume_id/lib/ufs.c
new file mode 100644
index 0000000000..d3960b1bec
--- /dev/null
+++ b/extras/volume_id/lib/ufs.c
@@ -0,0 +1,210 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.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;
+ } PACKED 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];
+ } PACKED 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];
+ } PACKED fs_cstotal;
+ struct ufs_timeval {
+ int32_t tv_sec;
+ int32_t tv_usec;
+ } PACKED fs_time;
+ int64_t fs_size;
+ int64_t fs_dsize;
+ uint64_t fs_csaddr;
+ int64_t fs_pendingblocks;
+ int32_t fs_pendinginodes;
+ } 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];
+ } PACKED 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];
+ } PACKED 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;
+ } PACKED 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];
+} PACKED;
+
+#define UFS_MAGIC 0x00011954
+#define UFS2_MAGIC 0x19540119
+#define UFS_MAGIC_FEA 0x00195612
+#define UFS_MAGIC_LFN 0x00095014
+
+int volume_id_probe_ufs(struct volume_id *id, uint64_t off)
+{
+ uint32_t magic;
+ int i;
+ struct ufs_super_block *ufs;
+ int offsets[] = {0, 8, 64, 256, -1};
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ for (i = 0; offsets[i] >= 0; i++) {
+ ufs = (struct ufs_super_block *) volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800);
+ if (ufs == NULL)
+ return -1;
+
+ dbg("offset 0x%x", offsets[i] * 0x400);
+ magic = be32_to_cpu(ufs->fs_magic);
+ if ((magic == UFS_MAGIC) ||
+ (magic == UFS2_MAGIC) ||
+ (magic == UFS_MAGIC_FEA) ||
+ (magic == UFS_MAGIC_LFN)) {
+ dbg("magic 0x%08x(be)", magic);
+ goto found;
+ }
+ magic = le32_to_cpu(ufs->fs_magic);
+ if ((magic == UFS_MAGIC) ||
+ (magic == UFS2_MAGIC) ||
+ (magic == UFS_MAGIC_FEA) ||
+ (magic == UFS_MAGIC_LFN)) {
+ dbg("magic 0x%08x(le)", magic);
+ goto found;
+ }
+ }
+ return -1;
+
+found:
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "ufs";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/util.c b/extras/volume_id/lib/util.c
new file mode 100644
index 0000000000..cf5392cf9a
--- /dev/null
+++ b/extras/volume_id/lib/util.c
@@ -0,0 +1,267 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count)
+{
+ unsigned int i, j;
+ uint16_t c;
+
+ j = 0;
+ for (i = 0; i + 2 <= count; i += 2) {
+ if (endianess == LE)
+ c = (buf[i+1] << 8) | buf[i];
+ else
+ c = (buf[i] << 8) | buf[i+1];
+ if (c == 0) {
+ str[j] = '\0';
+ break;
+ } else if (c < 0x80) {
+ if (j+1 >= len)
+ break;
+ str[j++] = (uint8_t) c;
+ } else if (c < 0x800) {
+ if (j+2 >= len)
+ break;
+ str[j++] = (uint8_t) (0xc0 | (c >> 6));
+ str[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ } else {
+ if (j+3 >= len)
+ break;
+ str[j++] = (uint8_t) (0xe0 | (c >> 12));
+ str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+ str[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ }
+ }
+ str[j] = '\0';
+}
+
+static char *usage_to_string(enum volume_id_usage usage_id)
+{
+ switch (usage_id) {
+ case VOLUME_ID_FILESYSTEM:
+ return "filesystem";
+ case VOLUME_ID_OTHER:
+ return "other";
+ case VOLUME_ID_RAID:
+ return "raid";
+ case VOLUME_ID_DISKLABEL:
+ return "disklabel";
+ case VOLUME_ID_CRYPTO:
+ return "crypto";
+ case VOLUME_ID_UNPROBED:
+ return "unprobed";
+ case VOLUME_ID_UNUSED:
+ return "unused";
+ }
+ return NULL;
+}
+
+void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id)
+{
+ id->usage_id = usage_id;
+ id->usage = usage_to_string(usage_id);
+}
+
+void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count)
+{
+ memcpy(id->label_raw, buf, count);
+ id->label_raw_len = count;
+}
+
+void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count)
+{
+ unsigned int i;
+
+ memcpy(id->label, buf, count);
+
+ /* remove trailing whitespace */
+ i = strnlen(id->label, count);
+ while (i--) {
+ if (!isspace(id->label[i]))
+ break;
+ }
+ id->label[i+1] = '\0';
+}
+
+void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count)
+{
+ volume_id_set_unicode16(id->label, sizeof(id->label), buf, endianess, count);
+}
+
+void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format)
+{
+ unsigned int i;
+ unsigned int count = 0;
+
+ switch(format) {
+ case UUID_DOS:
+ count = 4;
+ break;
+ case UUID_NTFS:
+ case UUID_HFS:
+ count = 8;
+ break;
+ case UUID_DCE:
+ count = 16;
+ break;
+ case UUID_DCE_STRING:
+ count = 36;
+ break;
+ }
+ memcpy(id->uuid_raw, buf, count);
+ id->uuid_raw_len = count;
+
+ /* if set, create string in the same format, the native platform uses */
+ for (i = 0; i < count; i++)
+ if (buf[i] != 0)
+ goto set;
+ return;
+
+set:
+ switch(format) {
+ case UUID_DOS:
+ sprintf(id->uuid, "%02X%02X-%02X%02X",
+ buf[3], buf[2], buf[1], buf[0]);
+ break;
+ case UUID_NTFS:
+ sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X",
+ buf[7], buf[6], buf[5], buf[4],
+ buf[3], buf[2], buf[1], buf[0]);
+ break;
+ case UUID_HFS:
+ sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+ break;
+ case UUID_DCE:
+ sprintf(id->uuid,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5],
+ buf[6], buf[7],
+ buf[8], buf[9],
+ buf[10], buf[11], buf[12], buf[13], buf[14],buf[15]);
+ break;
+ case UUID_DCE_STRING:
+ memcpy(id->uuid, buf, count);
+ id->uuid[count] = '\0';
+ break;
+ }
+}
+
+uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
+{
+ ssize_t buf_len;
+
+ dbg("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len);
+ /* check if requested area fits in superblock buffer */
+ if (off + len <= SB_BUFFER_SIZE) {
+ if (id->sbbuf == NULL) {
+ id->sbbuf = malloc(SB_BUFFER_SIZE);
+ if (id->sbbuf == NULL) {
+ dbg("error malloc");
+ return NULL;
+ }
+ }
+
+ /* check if we need to read */
+ if ((off + len) > id->sbbuf_len) {
+ dbg("read sbbuf len:0x%llx", (unsigned long long) (off + len));
+ if (lseek(id->fd, 0, SEEK_SET) < 0) {
+ dbg("lseek failed (%s)", strerror(errno));
+ return NULL;
+ }
+ buf_len = read(id->fd, id->sbbuf, off + len);
+ if (buf_len < 0) {
+ dbg("read failed (%s)", strerror(errno));
+ return NULL;
+ }
+ dbg("got 0x%zx (%zi) bytes", buf_len, buf_len);
+ id->sbbuf_len = buf_len;
+ if ((size_t)buf_len < off + len) {
+ dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len);
+ return NULL;
+ }
+ }
+
+ return &(id->sbbuf[off]);
+ } else {
+ if (len > SEEK_BUFFER_SIZE) {
+ dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
+ return NULL;
+ }
+
+ /* get seek buffer */
+ if (id->seekbuf == NULL) {
+ id->seekbuf = malloc(SEEK_BUFFER_SIZE);
+ if (id->seekbuf == NULL) {
+ dbg("error malloc");
+ return NULL;
+ }
+ }
+
+ /* check if we need to read */
+ if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
+ dbg("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len);
+ if (lseek(id->fd, off, SEEK_SET) < 0) {
+ dbg("lseek failed (%s)", strerror(errno));
+ return NULL;
+ }
+ buf_len = read(id->fd, id->seekbuf, len);
+ if (buf_len < 0) {
+ dbg("read failed (%s)", strerror(errno));
+ return NULL;
+ }
+ dbg("got 0x%zx (%zi) bytes", buf_len, buf_len);
+ id->seekbuf_off = off;
+ id->seekbuf_len = buf_len;
+ if ((size_t)buf_len < len) {
+ dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len);
+ return NULL;
+ }
+ }
+
+ return &(id->seekbuf[off - id->seekbuf_off]);
+ }
+}
+
+void volume_id_free_buffer(struct volume_id *id)
+{
+ if (id->sbbuf != NULL) {
+ free(id->sbbuf);
+ id->sbbuf = NULL;
+ id->sbbuf_len = 0;
+ }
+ if (id->seekbuf != NULL) {
+ free(id->seekbuf);
+ id->seekbuf = NULL;
+ id->seekbuf_len = 0;
+ }
+}
diff --git a/extras/volume_id/lib/util.h b/extras/volume_id/lib/util.h
new file mode 100644
index 0000000000..1d1b53bb57
--- /dev/null
+++ b/extras/volume_id/lib/util.h
@@ -0,0 +1,84 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _VOLUME_ID_UTIL_
+#define _VOLUME_ID_UTIL_
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <endian.h>
+#include <byteswap.h>
+#include <syslog.h>
+
+#define err(format, arg...) volume_id_log(LOG_ERR, __FILE__, __LINE__, format, ##arg)
+#define info(format, arg...) volume_id_log(LOG_INFO, __FILE__, __LINE__, format, ##arg)
+#ifdef DEBUG
+#define dbg(format, arg...) volume_id_log(LOG_DEBUG, __FILE__, __LINE__, format, ##arg)
+#else
+#define dbg(format, arg...) do { } while (0)
+#endif
+
+/* size of superblock buffer, reiserfs block is at 64k */
+#define SB_BUFFER_SIZE 0x11000
+/* size of seek buffer, FAT cluster is 32k max */
+#define SEEK_BUFFER_SIZE 0x10000
+
+#ifdef __BYTE_ORDER
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
+#define be16_to_cpu(x) bswap_16(x)
+#define be32_to_cpu(x) bswap_32(x)
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_be32(x) bswap_32(x)
+#elif (__BYTE_ORDER == __BIG_ENDIAN)
+#define le16_to_cpu(x) bswap_16(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define le64_to_cpu(x) bswap_64(x)
+#define be16_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_le16(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define cpu_to_be32(x) (x)
+#endif
+#endif /* __BYTE_ORDER */
+
+enum uuid_format {
+ UUID_DCE_STRING,
+ UUID_DCE,
+ UUID_DOS,
+ UUID_NTFS,
+ UUID_HFS,
+};
+
+enum endian {
+ LE = 0,
+ BE = 1
+};
+
+extern void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count);
+extern void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id);
+extern void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count);
+extern void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count);
+extern void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count);
+extern void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format);
+extern uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len);
+extern void volume_id_free_buffer(struct volume_id *id);
+
+#endif /* _VOLUME_ID_UTIL_ */
+
diff --git a/extras/volume_id/lib/via_raid.c b/extras/volume_id/lib/via_raid.c
new file mode 100644
index 0000000000..42cb098065
--- /dev/null
+++ b/extras/volume_id/lib/via_raid.c
@@ -0,0 +1,75 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct via_meta {
+ uint16_t signature;
+ uint8_t version_number;
+ struct via_array {
+ uint16_t disk_bits;
+ uint8_t disk_array_ex;
+ uint32_t capacity_low;
+ uint32_t capacity_high;
+ uint32_t serial_checksum;
+ } PACKED array;
+ uint32_t serial_checksum[8];
+ uint8_t checksum;
+} PACKED;
+
+#define VIA_SIGNATURE 0xAA55
+
+int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ const uint8_t *buf;
+ uint64_t meta_off;
+ struct via_meta *via;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-1) * 0x200;
+
+ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ via = (struct via_meta *) buf;
+ if (le16_to_cpu(via->signature) != VIA_SIGNATURE)
+ return -1;
+
+ if (via->version_number > 1)
+ return -1;
+
+ volume_id_set_usage(id, VOLUME_ID_RAID);
+ snprintf(id->type_version, sizeof(id->type_version)-1, "%u", via->version_number);
+ id->type = "via_raid_member";
+
+ return 0;
+}
diff --git a/extras/volume_id/lib/volume_id.c b/extras/volume_id/lib/volume_id.c
new file mode 100644
index 0000000000..073ad79c77
--- /dev/null
+++ b/extras/volume_id/lib/volume_id.c
@@ -0,0 +1,231 @@
+/*
+ * volume_id - reads volume label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+/* the user can overwrite this log function */
+static void default_log(int priority, const char *file, int line, const char *format, ...)
+{
+ return;
+}
+
+volume_id_log_fn volume_id_log = default_log;
+
+int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ if (id == NULL)
+ return -EINVAL;
+
+ /* probe for raid first, cause fs probes may be successful on raid members */
+ if (size) {
+ if (volume_id_probe_linux_raid(id, off, size) == 0)
+ goto found;
+
+ if (volume_id_probe_intel_software_raid(id, off, size) == 0)
+ goto found;
+
+ if (volume_id_probe_lsi_mega_raid(id, off, size) == 0)
+ goto found;
+
+ if (volume_id_probe_via_raid(id, off, size) == 0)
+ goto found;
+
+ if (volume_id_probe_silicon_medley_raid(id, off, size) == 0)
+ goto found;
+
+ if (volume_id_probe_nvidia_raid(id, off, size) == 0)
+ goto found;
+
+ if (volume_id_probe_promise_fasttrack_raid(id, off, size) == 0)
+ goto found;
+
+ if (volume_id_probe_highpoint_45x_raid(id, off, size) == 0)
+ goto found;
+ }
+
+ if (volume_id_probe_lvm1(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_lvm2(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_highpoint_37x_raid(id, off) == 0)
+ goto found;
+
+ return -1;
+
+found:
+ /* If recognized, we free the allocated buffers */
+ volume_id_free_buffer(id);
+ return 0;
+}
+
+int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ if (id == NULL)
+ return -EINVAL;
+
+ if (volume_id_probe_luks(id, off) == 0)
+ goto found;
+
+ /* signature in the first block, only small buffer needed */
+ if (volume_id_probe_vfat(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_xfs(id, off) == 0)
+ goto found;
+
+ /* fill buffer with maximum */
+ volume_id_get_buffer(id, 0, SB_BUFFER_SIZE);
+
+ if (volume_id_probe_linux_swap(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_ext(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_reiserfs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_jfs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_udf(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_iso9660(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_hfs_hfsplus(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_ufs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_ntfs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_cramfs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_romfs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_hpfs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_sysv(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_minix(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_ocfs1(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_ocfs2(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_vxfs(id, off) == 0)
+ goto found;
+
+ if (volume_id_probe_squashfs(id, off) == 0)
+ goto found;
+
+ return -1;
+
+found:
+ /* If recognized, we free the allocated buffers */
+ volume_id_free_buffer(id);
+ return 0;
+}
+
+int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ if (id == NULL)
+ return -EINVAL;
+
+ if (volume_id_probe_raid(id, off, size) == 0)
+ return 0;
+
+ if (volume_id_probe_filesystem(id, off, size) == 0)
+ return 0;
+
+ return -1;
+}
+
+/* open volume by already open file descriptor */
+struct volume_id *volume_id_open_fd(int fd)
+{
+ struct volume_id *id;
+
+ id = malloc(sizeof(struct volume_id));
+ if (id == NULL)
+ return NULL;
+ memset(id, 0x00, sizeof(struct volume_id));
+
+ id->fd = fd;
+
+ return id;
+}
+
+/* open volume by device node */
+struct volume_id *volume_id_open_node(const char *path)
+{
+ struct volume_id *id;
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ dbg("unable to open '%s'", path);
+ return NULL;
+ }
+
+ id = volume_id_open_fd(fd);
+ if (id == NULL)
+ return NULL;
+
+ /* close fd on device close */
+ id->fd_close = 1;
+
+ return id;
+}
+
+void volume_id_close(struct volume_id *id)
+{
+ if (id == NULL)
+ return;
+
+ if (id->fd_close != 0)
+ close(id->fd);
+
+ volume_id_free_buffer(id);
+
+ free(id);
+}
diff --git a/extras/volume_id/lib/vxfs.c b/extras/volume_id/lib/vxfs.c
new file mode 100644
index 0000000000..d10cc37762
--- /dev/null
+++ b/extras/volume_id/lib/vxfs.c
@@ -0,0 +1,54 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+#define VXFS_SUPER_MAGIC 0xa501FCF5
+
+struct vxfs_super {
+ uint32_t vs_magic;
+ int32_t vs_version;
+} PACKED;
+
+int volume_id_probe_vxfs(struct volume_id *id, uint64_t off)
+{
+ struct vxfs_super *vxs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ vxs = (struct vxfs_super *) volume_id_get_buffer(id, off + 0x200, 0x200);
+ if (vxs == NULL)
+ return -1;
+
+ if (vxs->vs_magic == cpu_to_le32(VXFS_SUPER_MAGIC)) {
+ snprintf(id->type_version, sizeof(id->type_version)-1, "%u", (unsigned int) vxs->vs_version);
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "vxfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/extras/volume_id/lib/xfs.c b/extras/volume_id/lib/xfs.c
new file mode 100644
index 0000000000..3d870c41e7
--- /dev/null
+++ b/extras/volume_id/lib/xfs.c
@@ -0,0 +1,65 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "libvolume_id.h"
+#include "util.h"
+
+struct xfs_super_block {
+ uint8_t magic[4];
+ uint32_t blocksize;
+ uint64_t dblocks;
+ uint64_t rblocks;
+ uint32_t dummy1[2];
+ uint8_t uuid[16];
+ uint32_t dummy2[15];
+ uint8_t fname[12];
+ uint32_t dummy3[2];
+ uint64_t icount;
+ uint64_t ifree;
+ uint64_t fdblocks;
+} PACKED;
+
+int volume_id_probe_xfs(struct volume_id *id, uint64_t off)
+{
+ struct xfs_super_block *xs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ xs = (struct xfs_super_block *) volume_id_get_buffer(id, off, 0x200);
+ if (xs == NULL)
+ return -1;
+
+ if (memcmp(xs->magic, "XFSB", 4) != 0)
+ return -1;
+
+ volume_id_set_label_raw(id, xs->fname, 12);
+ volume_id_set_label_string(id, xs->fname, 12);
+ volume_id_set_uuid(id, xs->uuid, UUID_DCE);
+
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ id->type = "xfs";
+
+ return 0;
+}