chiark / gitweb /
[PATCH] update udev_volume_id
authorkay.sievers@vrfy.org <kay.sievers@vrfy.org>
Sun, 5 Sep 2004 16:05:36 +0000 (18:05 +0200)
committerGreg KH <gregkh@suse.de>
Wed, 27 Apr 2005 04:37:00 +0000 (21:37 -0700)
Here is an update for the volume_id callout to catch up to the latest
and greatest:

o It is able to skip the label reading of linux raid members, which are
  otherwise recognized as a normal filesystem.

o It reads FAT labels stored in the directory instead of the
  superblock (Windows only writes in the directory).

o The NTFS uuid is the right one now.

o It reads all the Apple HFS(+) formats with the labels.

o UFS volumes are recognized but no labels are extracted.

o We use CFLAGS+=-D_FILE_OFFSET_BITS=64 instead of lsee64() which may fix
  a bug mentioned on the klibc mailing list.

A lot of other new features are only used in HAL and not needed in this
simple callout. But if someone stumbles over it and want's to send a patch
for some exotic formats, we better keep it up to date :)

extras/volume_id/Makefile
extras/volume_id/udev_volume_id.c
extras/volume_id/volume_id.c
extras/volume_id/volume_id.h

index 307fdc2..8813f9f 100644 (file)
@@ -28,7 +28,11 @@ INSTALL_PROGRAM = ${INSTALL}
 INSTALL_DATA  = ${INSTALL} -m 644
 INSTALL_SCRIPT = ${INSTALL_PROGRAM}
 
-override CFLAGS+=-Wall -fno-builtin
+override CFLAGS+=-Wall -fno-builtin -Wchar-subscripts -Wmissing-declarations \
+                -Wnested-externs -Wpointer-arith -Wcast-align \
+                -Wsign-compare
+
+override CFLAGS+=-D_FILE_OFFSET_BITS=64
 
 SYSFS =        ../../libsysfs/sysfs_bus.o      \
        ../../libsysfs/sysfs_class.o    \
index 18915cb..e884450 100644 (file)
@@ -25,6 +25,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
 
 #include "../../libsysfs/sysfs/libsysfs.h"
 #include "../../udev_lib.h"
@@ -71,6 +73,36 @@ static struct volume_id *open_classdev(struct sysfs_class_device *class_dev)
        return vid;
 }
 
+static unsigned long long get_size(struct volume_id *vid)
+{
+       unsigned long long size;
+
+       if (ioctl(vid->fd, BLKGETSIZE64, &size) != 0)
+               size = 0;
+
+       return size;
+}
+
+static char *usage_id_name(enum volume_id_usage usage)
+{
+       switch(usage) {
+       case VOLUME_ID_UNUSED:
+               return "unused";
+       case VOLUME_ID_UNPROBED:
+               return "unprobed";
+       case VOLUME_ID_OTHER:
+               return "other";
+       case VOLUME_ID_PARTITIONTABLE:
+               return "partitiontable";
+       case VOLUME_ID_FILESYSTEM:
+               return "filesystem";
+       case VOLUME_ID_RAID:
+               return "raid";
+       default:
+               return "unknown type_id";
+       }
+}
+
 int main(int argc, char *argv[])
 {
        const char help[] = "usage: udev_volume_id [-t|-l|-u|-d]\n"
@@ -80,7 +112,6 @@ int main(int argc, char *argv[])
                            "       -d disk label from main device\n"
                            "\n";
        static const char short_options[] = "htlud";
-       int option;
        char sysfs_path[SYSFS_PATH_MAX];
        char dev_path[SYSFS_PATH_MAX];
        struct sysfs_class_device *class_dev = NULL;
@@ -92,9 +123,12 @@ int main(int argc, char *argv[])
        char dasd_label[7];
        static char name[VOLUME_ID_LABEL_SIZE];
        int len, i, j;
+       unsigned long long size;
        int rc = 1;
 
        while (1) {
+               int option;
+
                option = getopt(argc, argv, short_options);
                if (option == -1)
                        break;
@@ -146,24 +180,26 @@ int main(int argc, char *argv[])
                vid = open_classdev(class_dev);
                if (vid == NULL)
                        goto exit;
-               if (volume_id_probe(vid, ALL) == 0)
+
+               size = get_size(vid);
+
+               if (volume_id_probe(vid, VOLUME_ID_ALL, 0, size) == 0)
                        goto print;
                break;
        case 'd' :
-               /* if we are on a partition, close it and open main block device */
+               /* if we are on a partition, open main block device instead */
                class_dev_parent = sysfs_get_classdev_parent(class_dev);
-               if (class_dev_parent != NULL) {
-                       volume_id_close(vid);
+               if (class_dev_parent != NULL)
                        vid = open_classdev(class_dev_parent);
-               } else {
+               else
                        vid = open_classdev(class_dev_parent);
-               }
                if (vid == NULL)
                        goto exit;
+
                if (probe_ibm_partition(vid->fd, dasd_label) == 0) {
-                       vid->fs_name = "dasd";
-                       strncpy(vid->label_string, dasd_label, 6);
-                       vid->label_string[6] = '\0';
+                       vid->type = "dasd";
+                       strncpy(vid->label, dasd_label, 6);
+                       vid->label[6] = '\0';
                        goto print;
                }
                break;
@@ -174,10 +210,10 @@ int main(int argc, char *argv[])
 
 
 print:
-       len = strnlen(vid->label_string, VOLUME_ID_LABEL_SIZE);
+       len = strnlen(vid->label, VOLUME_ID_LABEL_SIZE);
 
        /* remove trailing spaces */
-       while (len > 0 && isspace(vid->label_string[len-1]))
+       while (len > 0 && isspace(vid->label[len-1]))
                len--;
        name[len] = '\0';
 
@@ -185,14 +221,14 @@ print:
        i = 0;
        j = 0;
        while (j < len) {
-               switch(vid->label_string[j]) {
+               switch(vid->label[j]) {
                case '/' :
                        break;
                case ' ' :
                        name[i++] = '_';
                        break;
                default :
-                       name[i++] = vid->label_string[j];
+                       name[i++] = vid->label[j];
                }
                j++;
        }
@@ -200,27 +236,29 @@ print:
 
        switch (print) {
        case 't':
-               printf("%s\n", vid->fs_name);
+               printf("%s\n", vid->type);
                break;
        case 'l':
-               if (name[0] == '\0') {
+               if (name[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
                        rc = 2;
                        goto exit;
                }
                printf("%s\n", name);
                break;
        case 'u':
-               if (vid->uuid_string[0] == '\0') {
+               if (vid->uuid[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
                        rc = 2;
                        goto exit;
                }
-               printf("%s\n", vid->uuid_string);
+               printf("%s\n", vid->uuid);
                break;
        case 'a':
-               printf("T:%s\n", vid->fs_name);
-               printf("L:%s\n", vid->label_string);
+               printf("F:%s\n", usage_id_name(vid->usage_id));
+               printf("T:%s\n", vid->type);
+               printf("V:%s\n", vid->type_version);
+               printf("L:%s\n", vid->label);
                printf("N:%s\n", name);
-               printf("U:%s\n", vid->uuid_string);
+               printf("U:%s\n", vid->uuid);
        }
        rc = 0;
 
index ac7e76b..daeb000 100644 (file)
@@ -3,13 +3,10 @@
  *
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
- *     The superblock structs are taken from the libblkid living inside
- *     the e2fsprogs. This is a simple straightforward implementation for
- *     reading the label strings of only the most common filesystems.
- *     If you need a full featured library with attribute caching, support for
- *     much more partition/media types or non-root disk access, you may have
- *     a look at:
- *             http://e2fsprogs.sourceforge.net.
+ *     The superblock structs are taken from the linux kernel sources
+ *     and the libblkid living inside the e2fsprogs. This is a simple
+ *     straightforward implementation for reading the label strings of the
+ *     most common filesystems.
  *
  *     This library is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU Lesser General Public
 #define _GNU_SOURCE
 #endif
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -49,7 +50,7 @@
        } while (0)
 #else
 #define dbg(format, arg...)    do {} while (0)
-#endif
+#endif /* DEBUG */
 
 #define bswap16(x) (__u16)((((__u16)(x) & 0x00ffu) << 8) | \
                           (((__u32)(x) & 0xff00u) >> 8))
                           (((__u64)(x) & 0x000000000000ff00u) << 40) | \
                           (((__u64)(x) & 0x00000000000000ffu) << 56))
 
-#if (__BYTE_ORDER == __LITTLE_ENDIAN) 
+#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) bswap16(x)
+#define be32_to_cpu(x) bswap32(x)
 #elif (__BYTE_ORDER == __BIG_ENDIAN)
 #define le16_to_cpu(x) bswap16(x)
 #define le32_to_cpu(x) bswap32(x)
 #define le64_to_cpu(x) bswap64(x)
+#define be16_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
 #endif
 
-/* size of superblock buffer, reiser block is at 64k */
+/* size of superblock buffer, reiserfs block is at 64k */
 #define SB_BUFFER_SIZE                         0x11000
-/* size of seek buffer 2k */
-#define SEEK_BUFFER_SIZE                       0x800
+/* size of seek buffer 4k */
+#define SEEK_BUFFER_SIZE                       0x1000
 
 
 static void set_label_raw(struct volume_id *id,
@@ -96,15 +101,15 @@ static void set_label_string(struct volume_id *id,
 {
        unsigned int i;
 
-       memcpy(id->label_string, buf, count);
+       memcpy(id->label, buf, count);
 
        /* remove trailing whitespace */
-       i = strnlen(id->label_string, count);
+       i = strnlen(id->label, count);
        while (i--) {
-               if (! isspace(id->label_string[i]))
+               if (! isspace(id->label[i]))
                        break;
        }
-       id->label_string[i+1] = '\0';
+       id->label[i+1] = '\0';
 }
 
 #define LE             0
@@ -118,23 +123,23 @@ static void set_label_unicode16(struct volume_id *id,
        __u16 c;
 
        j = 0;
-       for (i = 0; i <= count-2; i += 2) {
+       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) {
-                       id->label_string[j] = '\0';
+                       id->label[j] = '\0';
                        break;
                } else if (c < 0x80) {
-                       id->label_string[j++] = (__u8) c;
+                       id->label[j++] = (__u8) c;
                } else if (c < 0x800) {
-                       id->label_string[j++] = (__u8) (0xc0 | (c >> 6));
-                       id->label_string[j++] = (__u8) (0x80 | (c & 0x3f));
+                       id->label[j++] = (__u8) (0xc0 | (c >> 6));
+                       id->label[j++] = (__u8) (0x80 | (c & 0x3f));
                } else {
-                       id->label_string[j++] = (__u8) (0xe0 | (c >> 12));
-                       id->label_string[j++] = (__u8) (0x80 | ((c >> 6) & 0x3f));
-                       id->label_string[j++] = (__u8) (0x80 | (c & 0x3f));
+                       id->label[j++] = (__u8) (0xe0 | (c >> 12));
+                       id->label[j++] = (__u8) (0x80 | ((c >> 6) & 0x3f));
+                       id->label[j++] = (__u8) (0x80 | (c & 0x3f));
                }
        }
 }
@@ -144,10 +149,10 @@ static void set_uuid(struct volume_id *id,
 {
        unsigned int i;
 
-       memcpy(id->uuid, buf, count);
+       memcpy(id->uuid_raw, buf, count);
 
        /* create string if uuid is set */
-       for (i = 0; i < count; i++) 
+       for (i = 0; i < count; i++)
                if (buf[i] != 0)
                        goto set;
        return;
@@ -155,11 +160,16 @@ static void set_uuid(struct volume_id *id,
 set:
        switch(count) {
        case 4:
-               sprintf(id->uuid_string, "%02X%02X-%02X%02X",
+               sprintf(id->uuid, "%02X%02X-%02X%02X",
+                       buf[3], buf[2], buf[1], buf[0]);
+               break;
+       case 8:
+               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 16:
-               sprintf(id->uuid_string,
+               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],
@@ -171,11 +181,11 @@ set:
        }
 }
 
-static __u8 *get_buffer(struct volume_id *id,
-                       unsigned long off, unsigned int len)
+static __u8 *get_buffer(struct volume_id *id, __u64 off, unsigned int len)
 {
        unsigned int buf_len;
 
+       dbg("get buffer off 0x%llx, len 0x%x", off, len);
        /* check if requested area fits in superblock buffer */
        if (off + len <= SB_BUFFER_SIZE) {
                if (id->sbbuf == NULL) {
@@ -186,9 +196,10 @@ static __u8 *get_buffer(struct volume_id *id,
 
                /* check if we need to read */
                if ((off + len) > id->sbbuf_len) {
-                       dbg("read sbbuf len:0x%lx", off + len);
-                       lseek64(id->fd, 0, SEEK_SET);
+                       dbg("read sbbuf len:0x%llx", off + len);
+                       lseek(id->fd, 0, SEEK_SET);
                        buf_len = read(id->fd, id->sbbuf, off + len);
+                       dbg("got 0x%x (%i) bytes", buf_len, buf_len);
                        id->sbbuf_len = buf_len;
                        if (buf_len < off + len)
                                return NULL;
@@ -209,8 +220,9 @@ static __u8 *get_buffer(struct volume_id *id,
                /* check if we need to read */
                if ((off < id->seekbuf_off) ||
                    ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
-                       dbg("read seekbuf off:0x%lx len:0x%x", off, len);
-                       lseek64(id->fd, off, SEEK_SET);
+                       dbg("read seekbuf off:0x%llx len:0x%x", off, len);
+                       if (lseek(id->fd, off, SEEK_SET) == -1)
+                               return NULL;
                        buf_len = read(id->fd, id->seekbuf, len);
                        dbg("got 0x%x (%i) bytes", buf_len, buf_len);
                        id->seekbuf_off = off;
@@ -237,10 +249,298 @@ static void free_buffer(struct volume_id *id)
        }
 }
 
+#define LVM1_SB_OFF                    0x400
+#define LVM1_MAGIC                     "HM"
+static int probe_lvm1(struct volume_id *id, __u64 off)
+{
+       struct lvm2_super_block {
+               __u8    id[2];
+       } __attribute__((packed)) *lvm;
+
+       const __u8 *buf;
+
+       buf = get_buffer(id, off + LVM1_SB_OFF, 0x800);
+       if (buf == NULL)
+               return -1;
+
+       lvm = (struct lvm2_super_block *) buf;
+
+       if (strncmp(lvm->id, LVM1_MAGIC, 2) != 0)
+               return -1;
+
+       id->usage_id = VOLUME_ID_RAID;
+       id->type_id = VOLUME_ID_LVM1;
+       id->type = "LVM1_member";
+
+       return 0;
+}
+
+#define LVM2_LABEL_ID                  "LABELONE"
+#define LVM2LABEL_SCAN_SECTORS         4
+static int probe_lvm2(struct volume_id *id, __u64 off)
+{
+       struct lvm2_super_block {
+               __u8    id[8];
+               __u64   sector_xl;
+               __u32   crc_xl;
+               __u32   offset_xl;
+               __u8    type[8];
+       } __attribute__((packed)) *lvm;
+
+       const __u8 *buf;
+       unsigned int soff;
+
+       buf = 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 (strncmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
+                       goto found;
+       }
+
+       return -1;
+
+found:
+       strncpy(id->type_version, lvm->type, 8);
+       id->usage_id = VOLUME_ID_RAID;
+       id->type_id = VOLUME_ID_LVM1;
+       id->type = "LVM2_member";
+
+       return 0;
+}
+
+#define MD_RESERVED_BYTES              0x10000
+#define MD_MAGIC                       0xa92b4efc
+static int probe_linux_raid(struct volume_id *id, __u64 off, __u64 size)
+{
+       struct mdp_super_block {
+               __u32   md_magic;
+               __u32   major_version;
+               __u32   minor_version;
+               __u32   patch_version;
+               __u32   gvalid_words;
+               __u32   set_uuid0;
+               __u32   ctime;
+               __u32   level;
+               __u32   size;
+               __u32   nr_disks;
+               __u32   raid_disks;
+               __u32   md_minor;
+               __u32   not_persistent;
+               __u32   set_uuid1;
+               __u32   set_uuid2;
+               __u32   set_uuid3;
+       } __attribute__((packed)) *mdp;
+
+       const __u8 *buf;
+       __u64 sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
+       __u8 uuid[16];
+
+       if (size < 0x10000)
+               return -1;
+
+       buf = 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);
+       set_uuid(id, uuid, 16);
+
+       snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-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");
+       id->usage_id = VOLUME_ID_RAID;
+       id->type = "linux_raid_member";
+
+       return 0;
+}
+
+#define MSDOS_MAGIC                    "\x55\xaa"
+#define MSDOS_PARTTABLE_OFFSET         0x1be
+#define MSDOS_SIG_OFF                  0x1fe
+#define BSIZE                          0x200
+#define DOS_EXTENDED_PARTITION         0x05
+#define LINUX_EXTENDED_PARTITION       0x85
+#define WIN98_EXTENDED_PARTITION       0x0f
+#define LINUX_RAID_PARTITION           0xfd
+#define is_extended(type) \
+       (type == DOS_EXTENDED_PARTITION ||      \
+        type == WIN98_EXTENDED_PARTITION ||    \
+        type == LINUX_EXTENDED_PARTITION)
+#define is_raid(type) \
+       (type == LINUX_RAID_PARTITION)
+static int probe_msdos_part_table(struct volume_id *id, __u64 off)
+{
+       struct msdos_partition_entry {
+               __u8    boot_ind;
+               __u8    head;
+               __u8    sector;
+               __u8    cyl;
+               __u8    sys_ind;
+               __u8    end_head;
+               __u8    end_sector;
+               __u8    end_cyl;
+               __u32   start_sect;
+               __u32   nr_sects;
+       } __attribute__((packed)) *part;
+
+       const __u8 *buf;
+       int i;
+       __u64 poff;
+       __u64 plen;
+       __u64 extended = 0;
+       __u64 current;
+       __u64 next;
+       int limit;
+       int empty = 1;
+       struct volume_id_partition *p;
+
+       buf = get_buffer(id, off, 0x200);
+       if (buf == NULL)
+               return -1;
+
+       if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
+               return -1;
+
+       /* check flags on all entries for a valid partition table */
+       part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
+       for (i = 0; i < 4; i++) {
+               if (part[i].boot_ind != 0 &&
+                   part[i].boot_ind != 0x80)
+                       return -1;
+
+               if (le32_to_cpu(part[i].nr_sects) != 0)
+                       empty = 0;
+       }
+       if (empty == 1)
+               return -1;
+
+       if (id->partitions != NULL)
+               free(id->partitions);
+       id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
+                               sizeof(struct volume_id_partition));
+       if (id->partitions == NULL)
+               return -1;
+       memset(id->partitions, 0x00,
+              VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
+
+       for (i = 0; i < 4; i++) {
+               poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
+               plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
+
+               if (plen == 0)
+                       continue;
+
+               p = &id->partitions[i];
+
+               if (is_extended(part[i].sys_ind)) {
+                       dbg("found extended partition at 0x%llx", poff);
+                       p->usage_id = VOLUME_ID_PARTITIONTABLE;
+                       p->type_id = VOLUME_ID_MSDOSEXTENDED;
+                       p->type = "msdos_extended_partition";
+                       if (extended == 0)
+                               extended = off + poff;
+               } else {
+                       dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
+                           part[i].sys_ind, poff, plen);
+
+                       if (is_raid(part[i].sys_ind))
+                               p->usage_id = VOLUME_ID_RAID;
+                       else
+                               p->usage_id = VOLUME_ID_UNPROBED;
+               }
+
+               p->off = off + poff;
+               p->len = plen;
+               id->partition_count = i+1;
+       }
+
+       next = extended;
+       current = extended;
+       limit = 50;
+
+       /* follow extended partition chain and add data partitions */
+       while (next != 0) {
+               if (limit-- == 0) {
+                       dbg("extended chain limit reached");
+                       break;
+               }
+
+               buf = get_buffer(id, current, 0x200);
+               if (buf == NULL)
+                       break;
+
+               part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
+
+               if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
+                       break;
+
+               next = 0;
+
+               for (i = 0; i < 4; i++) {
+                       poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
+                       plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
+
+                       if (plen == 0)
+                               continue;
+
+                       if (is_extended(part[i].sys_ind)) {
+                               dbg("found extended partition at 0x%llx", poff);
+                               if (next == 0)
+                                       next = extended + poff;
+                       } else {
+                               dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
+                                       part[i].sys_ind, poff, plen);
+
+                               /* we always start at the 5th entry */
+                               while (id->partition_count < 4)
+                                       id->partitions[id->partition_count++].usage_id =
+                                               VOLUME_ID_UNUSED;
+
+                               p = &id->partitions[id->partition_count];
+
+                               if (is_raid(part[i].sys_ind))
+                                       p->usage_id = VOLUME_ID_RAID;
+                               else
+                                       p->usage_id = VOLUME_ID_UNPROBED;
+
+                               p->off = current + poff;
+                               p->len = plen;
+                               id->partition_count++;
+                               if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
+                                       dbg("to many partitions");
+                                       next = 0;
+                               }
+                       }
+               }
+
+               current = next;
+       }
+
+       id->usage_id = VOLUME_ID_PARTITIONTABLE;
+       id->type_id = VOLUME_ID_MSDOSPARTTABLE;
+       id->type = "msdos_partition_table";
+
+       return 0;
+}
+
 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL                0x00000004
 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV      0x00000008
 #define EXT_SUPERBLOCK_OFFSET                  0x400
-static int probe_ext(struct volume_id *id)
+static int probe_ext(struct volume_id *id, __u64 off)
 {
        struct ext2_super_block {
                __u32   inodes_count;
@@ -262,7 +562,7 @@ static int probe_ext(struct volume_id *id)
        } __attribute__((__packed__)) *es;
 
        es = (struct ext2_super_block *)
-            get_buffer(id, EXT_SUPERBLOCK_OFFSET, 0x200);
+            get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
        if (es == NULL)
                return -1;
 
@@ -276,21 +576,23 @@ static int probe_ext(struct volume_id *id)
 
        if ((le32_to_cpu(es->feature_compat) &
             EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
-               id->fs_type = EXT3;
-               id->fs_name = "ext3";
+               id->usage_id = VOLUME_ID_FILESYSTEM;
+               id->type_id = VOLUME_ID_EXT3;
+               id->type = "ext3";
        } else {
-               id->fs_type = EXT2;
-               id->fs_name = "ext2";
+               id->usage_id = VOLUME_ID_FILESYSTEM;
+               id->type_id = VOLUME_ID_EXT2;
+               id->type = "ext2";
        }
 
        return 0;
 }
 
-#define REISER1_SUPERBLOCK_OFFSET              0x2000
-#define REISER_SUPERBLOCK_OFFSET               0x10000
-static int probe_reiser(struct volume_id *id)
+#define REISERFS1_SUPERBLOCK_OFFSET            0x2000
+#define REISERFS_SUPERBLOCK_OFFSET             0x10000
+static int probe_reiserfs(struct volume_id *id, __u64 off)
 {
-       struct reiser_super_block {
+       struct reiserfs_super_block {
                __u32   blocks_count;
                __u32   free_blocks;
                __u32   root_block;
@@ -306,23 +608,30 @@ static int probe_reiser(struct volume_id *id)
                __u8    label[16];
        } __attribute__((__packed__)) *rs;
 
-       rs = (struct reiser_super_block *)
-            get_buffer(id, REISER_SUPERBLOCK_OFFSET, 0x200);
+       rs = (struct reiserfs_super_block *)
+            get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
        if (rs == NULL)
                return -1;
 
-       if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0)
+       if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
+               strcpy(id->type_version, "3.6");
                goto found;
-       if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0)
+       }
+
+       if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
+               strcpy(id->type_version, "JR");
                goto found;
+       }
 
-       rs = (struct reiser_super_block *)
-            get_buffer(id, REISER1_SUPERBLOCK_OFFSET, 0x200);
+       rs = (struct reiserfs_super_block *)
+            get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
        if (rs == NULL)
                return -1;
 
-       if (strncmp(rs->magic, "ReIsErFs", 8) == 0)
+       if (strncmp(rs->magic, "ReIsErFs", 8) == 0) {
+               strcpy(id->type_version, "3.5");
                goto found;
+       }
 
        return -1;
 
@@ -331,13 +640,14 @@ found:
        set_label_string(id, rs->label, 16);
        set_uuid(id, rs->uuid, 16);
 
-       id->fs_type = REISER;
-       id->fs_name = "reiser";
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_REISERFS;
+       id->type = "reiserfs";
 
        return 0;
 }
 
-static int probe_xfs(struct volume_id *id)
+static int probe_xfs(struct volume_id *id, __u64 off)
 {
        struct xfs_super_block {
                __u8    magic[4];
@@ -354,7 +664,7 @@ static int probe_xfs(struct volume_id *id)
                __u64   fdblocks;
        } __attribute__((__packed__)) *xs;
 
-       xs = (struct xfs_super_block *) get_buffer(id, 0, 0x200);
+       xs = (struct xfs_super_block *) get_buffer(id, off, 0x200);
        if (xs == NULL)
                return -1;
 
@@ -365,14 +675,15 @@ static int probe_xfs(struct volume_id *id)
        set_label_string(id, xs->fname, 12);
        set_uuid(id, xs->uuid, 16);
 
-       id->fs_type = XFS;
-       id->fs_name = "xfs";
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_XFS;
+       id->type = "xfs";
 
        return 0;
 }
 
 #define JFS_SUPERBLOCK_OFFSET                  0x8000
-static int probe_jfs(struct volume_id *id)
+static int probe_jfs(struct volume_id *id, __u64 off)
 {
        struct jfs_super_block {
                __u8    magic[4];
@@ -388,7 +699,7 @@ static int probe_jfs(struct volume_id *id)
        } __attribute__((__packed__)) *js;
 
        js = (struct jfs_super_block *)
-            get_buffer(id, JFS_SUPERBLOCK_OFFSET, 0x200);
+            get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
        if (js == NULL)
                return -1;
 
@@ -399,115 +710,294 @@ static int probe_jfs(struct volume_id *id)
        set_label_string(id, js->label, 16);
        set_uuid(id, js->uuid, 16);
 
-       id->fs_type = JFS;
-       id->fs_name = "jfs";
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_JFS;
+       id->type = "jfs";
 
        return 0;
 }
 
-static int probe_vfat(struct volume_id *id)
+#define FAT12_MAX                      0xff5
+#define FAT16_MAX                      0xfff5
+#define FAT_ATTR_VOLUME                        0x08
+struct vfat_dir_entry {
+       __u8    name[11];
+       __u8    attr;
+       __u16   time_creat;
+       __u16   date_creat;
+       __u16   time_acc;
+       __u16   date_acc;
+       __u16   cluster_high;
+       __u16   time_write;
+       __u16   date_write;
+       __u16   cluster_low;
+       __u32   size;
+} __attribute__((__packed__));
+
+static  char *vfat_search_label_in_dir(const __u8 *buf, __u16 size)
+{
+       struct vfat_dir_entry *dir;
+       int i;
+       __u16 count;
+
+       dir = (struct vfat_dir_entry*) buf;
+       count = size / sizeof(struct vfat_dir_entry);
+       dbg("expected entries 0x%x", count);
+
+       for (i = 0; i <= count; i++) {
+               /* end marker */
+               if (dir[i].attr == 0x00) {
+                       dbg("end of dir");
+                       return NULL;
+               }
+
+               /* empty entry */
+               if (dir[i].attr == 0xe5)
+                       continue;
+
+               if (dir[i].attr == FAT_ATTR_VOLUME) {
+                       dbg("found ATTR_VOLUME id in root dir");
+                       return dir[i].name;
+               }
+
+               dbg("skip dir entry");
+       }
+
+       return NULL;
+}
+
+static int probe_vfat(struct volume_id *id, __u64 off)
 {
        struct vfat_super_block {
-               __u8    ignored[3];
+               __u8    boot_jump[3];
                __u8    sysid[8];
-               __u8    sector_size[2];
-               __u8    cluster_size;
+               __u16   sector_size;
+               __u8    sectors_per_cluster;
                __u16   reserved;
                __u8    fats;
-               __u8    dir_entries[2];
-               __u8    sectors[2];
+               __u16   dir_entries;
+               __u16   sectors;
                __u8    media;
                __u16   fat_length;
                __u16   secs_track;
                __u16   heads;
                __u32   hidden;
                __u32   total_sect;
-               __u32   fat32_length;
-               __u16   flags;
-               __u8    version[2];
-               __u32   root_cluster;
-               __u16   insfo_sector;
-               __u16   backup_boot;
-               __u16   reserved2[6];
-               __u8    unknown[3];
-               __u8    serno[4];
-               __u8    label[11];
-               __u8    magic[8];
-               __u8    dummy2[164];
-               __u8    pmagic[2];
+               union {
+                       struct fat_super_block {
+                               __u8    unknown[3];
+                               __u8    serno[4];
+                               __u8    label[11];
+                               __u8    magic[8];
+                               __u8    dummy2[192];
+                               __u8    pmagic[2];
+                       } __attribute__((__packed__)) fat;
+                       struct fat32_super_block {
+                               __u32   fat32_length;
+                               __u16   flags;
+                               __u8    version[2];
+                               __u32   root_cluster;
+                               __u16   insfo_sector;
+                               __u16   backup_boot;
+                               __u16   reserved2[6];
+                               __u8    unknown[3];
+                               __u8    serno[4];
+                               __u8    label[11];
+                               __u8    magic[8];
+                               __u8    dummy2[164];
+                               __u8    pmagic[2];
+                       } __attribute__((__packed__)) fat32;
+               } __attribute__((__packed__)) type;
        } __attribute__((__packed__)) *vs;
 
-       vs = (struct vfat_super_block *) get_buffer(id, 0, 0x200);
+       __u16 sector_size;
+       __u16 dir_entries;
+       __u32 sect_count;
+       __u16 reserved;
+       __u16 fat_size;
+       __u32 root_cluster;
+       __u32 dir_size;
+       __u32 cluster_count;
+       __u32 fat_length;
+       __u64 root_start;
+       __u32 start_data_sect;
+       __u16 root_dir_entries;
+       __u8 *buf;
+       __u32 buf_size;
+       __u8 *label = NULL;
+       __u32 next;
+
+       vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
        if (vs == NULL)
                return -1;
 
-       if (strncmp(vs->magic, "MSWIN", 5) == 0)
-               goto found;
-       if (strncmp(vs->magic, "FAT32   ", 8) == 0)
-               goto found;
-       return -1;
+       /* believe only that's fat, don't trust the version
+        * the cluster_count will tell us
+        */
+       if (strncmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
+               goto valid;
 
-found:
-       set_label_raw(id, vs->label, 11);
-       set_label_string(id, vs->label, 11);
-       set_uuid(id, vs->serno, 4);
+       if (strncmp(vs->type.fat32.magic, "FAT32   ", 8) == 0)
+               goto valid;
 
-       id->fs_type = VFAT;
-       id->fs_name = "vfat";
+       if (strncmp(vs->type.fat.magic, "FAT16   ", 8) == 0)
+               goto valid;
 
-       return 0;
-}
+       if (strncmp(vs->type.fat.magic, "MSDOS", 5) == 0)
+               goto valid;
 
-static int probe_msdos(struct volume_id *id)
-{
-       struct msdos_super_block {
-               __u8    ignored[3];
-               __u8    sysid[8];
-               __u8    sector_size[2];
-               __u8    cluster_size;
-               __u16   reserved;
-               __u8    fats;
-               __u8    dir_entries[2];
-               __u8    sectors[2];
-               __u8    media;
-               __u16   fat_length;
-               __u16   secs_track;
-               __u16   heads;
-               __u32   hidden;
-               __u32   total_sect;
-               __u8    unknown[3];
-               __u8    serno[4];
-               __u8    label[11];
-               __u8    magic[8];
-               __u8    dummy2[192];
-               __u8    pmagic[2];
-       } __attribute__((__packed__)) *ms;
-
-       ms = (struct msdos_super_block *) get_buffer(id, 0, 0x200);
-       if (ms == NULL)
+       if (strncmp(vs->type.fat.magic, "FAT12   ", 8) == 0)
+               goto valid;
+
+       /*
+        * There are old floppies out there without a magic, so we check
+        * for well known values and guess if it's a fat volume
+        */
+
+       /* boot jump address check */
+       if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
+            vs->boot_jump[0] != 0xe9)
                return -1;
 
-       if (strncmp(ms->magic, "MSDOS", 5) == 0)
-               goto found;
-       if (strncmp(ms->magic, "FAT16   ", 8) == 0)
-               goto found;
-       if (strncmp(ms->magic, "FAT12   ", 8) == 0)
+       /* heads check */
+       if (vs->heads == 0)
+               return -1;
+
+       /* cluster size check*/ 
+       if (vs->sectors_per_cluster == 0 ||
+           (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
+               return -1;
+
+       /* media check */
+       if (vs->media < 0xf8 && vs->media != 0xf0)
+               return -1;
+
+       /* fat count*/
+       if (vs->fats != 2)
+               return -1;
+
+valid:
+       /* 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 = vs->total_sect;
+       dbg("sect_count 0x%x", sect_count);
+
+       fat_length = le16_to_cpu(vs->fat_length);
+       if (fat_length == 0)
+               fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
+       dbg("fat_length 0x%x", fat_length);
+
+       fat_size = fat_length * vs->fats;
+       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);
+
+       if (cluster_count < FAT12_MAX) {
+               strcpy(id->type_version, "FAT12");
+       } else if (cluster_count < FAT16_MAX) {
+               strcpy(id->type_version, "FAT16");
+       } else {
+               strcpy(id->type_version, "FAT32");
+               goto fat32;
+       }
+
+       /* the label may be an attribute in the root directory */
+       root_start = (reserved + fat_size) * sector_size;
+       root_dir_entries = le16_to_cpu(vs->dir_entries);
+       dbg("root dir start 0x%x", root_start);
+
+       buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
+       buf = get_buffer(id, off + root_start, buf_size);
+       if (buf == NULL)
                goto found;
-       return -1;
 
-found:
-       set_label_raw(id, ms->label, 11);
-       set_label_string(id, ms->label, 11);
-       set_uuid(id, ms->serno, 4);
+       label = vfat_search_label_in_dir(buf, buf_size);
+
+       if (label != NULL && strncmp(label, "NO NAME    ", 11) != 0) {
+               set_label_raw(id, label, 11);
+               set_label_string(id, label, 11);
+       } else if (strncmp(vs->type.fat.label, "NO NAME    ", 11) != 0) {
+               set_label_raw(id, vs->type.fat.label, 11);
+               set_label_string(id, vs->type.fat.label, 11);
+       }
+       set_uuid(id, vs->type.fat.serno, 4);
+       goto found;
+
+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;
+       while (1) {
+               __u32 next_sect_off;
+               __u64 next_off;
+               __u64 fat_entry_off;
+
+               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%x", next_off);
+
+               /* get cluster */
+               buf = get_buffer(id, off + next_off, buf_size);
+               if (buf == NULL)
+                       goto found;
 
-       id->fs_type = MSDOS;
-       id->fs_name = "msdos";
+               label = vfat_search_label_in_dir(buf, buf_size);
+               if (label != NULL)
+                       break;
+
+               /* get FAT entry */
+               fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
+               buf = get_buffer(id, off + fat_entry_off, buf_size);
+               if (buf == NULL)
+                       goto found;
+
+               /* set next cluster */
+               next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
+               if (next == 0)
+                       break;
+       }
+
+       if (label != NULL && strncmp(label, "NO NAME    ", 11) != 0) {
+               set_label_raw(id, label, 11);
+               set_label_string(id, label, 11);
+       } else if (strncmp(vs->type.fat32.label, "NO NAME    ", 11) == 0) {
+               set_label_raw(id, vs->type.fat32.label, 11);
+               set_label_string(id, vs->type.fat32.label, 11);
+       }
+       set_uuid(id, vs->type.fat32.serno, 4);
+
+found:
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_VFAT;
+       id->type = "vfat";
 
        return 0;
 }
 
 #define UDF_VSD_OFFSET                 0x8000
-static int probe_udf(struct volume_id *id)
+static int probe_udf(struct volume_id *id, __u64 off)
 {
        struct volume_descriptor {
                struct descriptor_tag {
@@ -550,7 +1040,7 @@ static int probe_udf(struct volume_id *id)
        unsigned int clen;
 
        vsd = (struct volume_structure_descriptor *)
-             get_buffer(id, UDF_VSD_OFFSET, 0x200);
+             get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
        if (vsd == NULL)
                return -1;
 
@@ -574,7 +1064,7 @@ 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 *)
-                     get_buffer(id, UDF_VSD_OFFSET + bs, 0x800);
+                     get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
                if (vsd == NULL)
                        return -1;
                dbg("test for blocksize: 0x%x", bs);
@@ -587,7 +1077,7 @@ nsr:
        /* search the list of VSDs for a NSR descriptor */
        for (b = 0; b < 64; b++) {
                vsd = (struct volume_structure_descriptor *)
-                     get_buffer(id, UDF_VSD_OFFSET + (b * bs), 0x800);
+                     get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
                if (vsd == NULL)
                        return -1;
 
@@ -605,7 +1095,8 @@ nsr:
 
 anchor:
        /* read anchor volume descriptor */
-       vd = (struct volume_descriptor *) get_buffer(id, 256 * bs, 0x200);
+       vd = (struct volume_descriptor *)
+               get_buffer(id, off + (256 * bs), 0x200);
        if (vd == NULL)
                return -1;
 
@@ -621,7 +1112,7 @@ anchor:
        /* pick the primary descriptor from the list */
        for (b = 0; b < count; b++) {
                vd = (struct volume_descriptor *)
-                    get_buffer(id, (loc + b) * bs, 0x200);
+                    get_buffer(id, off + ((loc + b) * bs), 0x200);
                if (vd == NULL)
                        return -1;
 
@@ -644,20 +1135,21 @@ pvd:
 
        clen = vd->type.primary.ident.clen;
        dbg("label string charsize=%i bit", clen);
-       if (clen == 8) 
+       if (clen == 8)
                set_label_string(id, vd->type.primary.ident.c, 31);
        else if (clen == 16)
                set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
 
 found:
-       id->fs_type = UDF;
-       id->fs_name = "udf";
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_UDF;
+       id->type = "udf";
 
        return 0;
 }
 
 #define ISO_SUPERBLOCK_OFFSET          0x8000
-static int probe_iso9660(struct volume_id *id)
+static int probe_iso9660(struct volume_id *id, __u64 off)
 {
        union iso_super_block {
                struct iso_header {
@@ -677,7 +1169,7 @@ static int probe_iso9660(struct volume_id *id)
        } __attribute__((__packed__)) *is;
 
        is = (union iso_super_block *)
-            get_buffer(id, ISO_SUPERBLOCK_OFFSET, 0x200);
+            get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
        if (is == NULL)
                return -1;
 
@@ -691,40 +1183,557 @@ static int probe_iso9660(struct volume_id *id)
        return -1;
 
 found:
-       id->fs_type = ISO9660;
-       id->fs_name = "iso9660";
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_ISO9660;
+       id->type = "iso9660";
+
+       return 0;
+}
+
+#define UFS_MAGIC                      0x00011954
+#define UFS2_MAGIC                     0x19540119
+#define UFS_MAGIC_FEA                  0x00195612
+#define UFS_MAGIC_LFN                  0x00095014
+
+
+static int probe_ufs(struct volume_id *id, __u64 off)
+{
+       struct ufs_super_block {
+               __u32   fs_link;
+               __u32   fs_rlink;
+               __u32   fs_sblkno;
+               __u32   fs_cblkno;
+               __u32   fs_iblkno;
+               __u32   fs_dblkno;
+               __u32   fs_cgoffset;
+               __u32   fs_cgmask;
+               __u32   fs_time;
+               __u32   fs_size;
+               __u32   fs_dsize;
+               __u32   fs_ncg; 
+               __u32   fs_bsize;
+               __u32   fs_fsize;
+               __u32   fs_frag;
+               __u32   fs_minfree;
+               __u32   fs_rotdelay;
+               __u32   fs_rps; 
+               __u32   fs_bmask;
+               __u32   fs_fmask;
+               __u32   fs_bshift;
+               __u32   fs_fshift;
+               __u32   fs_maxcontig;
+               __u32   fs_maxbpg;
+               __u32   fs_fragshift;
+               __u32   fs_fsbtodb;
+               __u32   fs_sbsize;
+               __u32   fs_csmask;
+               __u32   fs_csshift;
+               __u32   fs_nindir;
+               __u32   fs_inopb;
+               __u32   fs_nspf;
+               __u32   fs_optim;
+               __u32   fs_npsect_state;
+               __u32   fs_interleave;
+               __u32   fs_trackskew;
+               __u32   fs_id[2];
+               __u32   fs_csaddr;
+               __u32   fs_cssize;
+               __u32   fs_cgsize;
+               __u32   fs_ntrak;
+               __u32   fs_nsect;
+               __u32   fs_spc; 
+               __u32   fs_ncyl;
+               __u32   fs_cpg;
+               __u32   fs_ipg;
+               __u32   fs_fpg;
+               struct ufs_csum {
+                       __u32   cs_ndir;
+                       __u32   cs_nbfree;
+                       __u32   cs_nifree;
+                       __u32   cs_nffree;
+               } __attribute__((__packed__)) fs_cstotal;
+               __s8    fs_fmod;
+               __s8    fs_clean;
+               __s8    fs_ronly;
+               __s8    fs_flags;
+               union {
+                       struct {
+                               __s8    fs_fsmnt[512];
+                               __u32   fs_cgrotor;
+                               __u32   fs_csp[31];
+                               __u32   fs_maxcluster;
+                               __u32   fs_cpc;
+                               __u16   fs_opostbl[16][8];
+                       } __attribute__((__packed__)) fs_u1;
+                       struct {
+                               __s8  fs_fsmnt[468];
+                               __u8   fs_volname[32];
+                               __u64  fs_swuid;
+                               __s32  fs_pad;
+                               __u32   fs_cgrotor;
+                               __u32   fs_ocsp[28];
+                               __u32   fs_contigdirs;
+                               __u32   fs_csp; 
+                               __u32   fs_maxcluster;
+                               __u32   fs_active;
+                               __s32   fs_old_cpc;
+                               __s32   fs_maxbsize;
+                               __s64   fs_sparecon64[17];
+                               __s64   fs_sblockloc;
+                               struct  ufs2_csum_total {
+                                       __u64   cs_ndir;
+                                       __u64   cs_nbfree;
+                                       __u64   cs_nifree;
+                                       __u64   cs_nffree;
+                                       __u64   cs_numclusters;
+                                       __u64   cs_spare[3];
+                               } __attribute__((__packed__)) fs_cstotal;
+                               struct  ufs_timeval {
+                                       __s32   tv_sec;
+                                       __s32   tv_usec;
+                               } __attribute__((__packed__)) fs_time;
+                               __s64    fs_size;
+                               __s64    fs_dsize;
+                               __u64    fs_csaddr;
+                               __s64    fs_pendingblocks;
+                               __s32    fs_pendinginodes;
+                       } __attribute__((__packed__)) fs_u2;
+               }  fs_u11;
+               union {
+                       struct {
+                               __s32   fs_sparecon[53];
+                               __s32   fs_reclaim;
+                               __s32   fs_sparecon2[1];
+                               __s32   fs_state;
+                               __u32   fs_qbmask[2];
+                               __u32   fs_qfmask[2];
+                       } __attribute__((__packed__)) fs_sun;
+                       struct {
+                               __s32   fs_sparecon[53];
+                               __s32   fs_reclaim;
+                               __s32   fs_sparecon2[1];
+                               __u32   fs_npsect;
+                               __u32   fs_qbmask[2];
+                               __u32   fs_qfmask[2];
+                       } __attribute__((__packed__)) fs_sunx86;
+                       struct {
+                               __s32   fs_sparecon[50];
+                               __s32   fs_contigsumsize;
+                               __s32   fs_maxsymlinklen;
+                               __s32   fs_inodefmt;
+                               __u32   fs_maxfilesize[2];
+                               __u32   fs_qbmask[2];
+                               __u32   fs_qfmask[2];
+                               __s32   fs_state;
+                       } __attribute__((__packed__)) fs_44;
+               } fs_u2;
+               __s32   fs_postblformat;
+               __s32   fs_nrpos;
+               __s32   fs_postbloff;
+               __s32   fs_rotbloff;
+               __u32   fs_magic;
+               __u8    fs_space[1];
+       } __attribute__((__packed__)) *ufs;
+
+       __u32   magic;
+       int     i;
+       int     offsets[] = {0, 8, 64, 256, -1};
+
+       for (i = 0; offsets[i] >= 0; i++) {     
+               ufs = (struct ufs_super_block *)
+                       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:
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_UFS;
+       id->type = "ufs";
+
+       return 0;
+}
+
+static int probe_mac_partition_map(struct volume_id *id, __u64 off)
+{
+       struct mac_driver_desc {
+               __u8    signature[2];
+               __u16   block_size;
+               __u32   block_count;
+       } __attribute__((__packed__)) *driver;
+
+       struct mac_partition {
+               __u8    signature[2];
+               __u16   res1;
+               __u32   map_count;
+               __u32   start_block;
+               __u32   block_count;
+               __u8    name[32];
+               __u8    type[32];
+       } __attribute__((__packed__)) *part;
+
+       const __u8 *buf;
+
+       buf = get_buffer(id, off, 0x200);
+       if (buf == NULL)
+               return -1;
+
+       part = (struct mac_partition *) buf;
+       if ((strncmp(part->signature, "PM", 2) == 0) &&
+           (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
+               /* linux creates an own subdevice for the map
+                * just return the type if the drive header is missing */
+               id->usage_id = VOLUME_ID_PARTITIONTABLE;
+               id->type_id = VOLUME_ID_MACPARTMAP;
+               id->type = "mac_partition_map";
+               return 0;
+       }
+
+       driver = (struct mac_driver_desc *) buf;
+       if (strncmp(driver->signature, "ER", 2) == 0) {
+               /* we are on a main device, like a CD
+                * just try to probe the first partition from the map */
+               unsigned int bsize = be16_to_cpu(driver->block_size);
+               int part_count;
+               int i;
+
+               /* get first entry of partition table */
+               buf = get_buffer(id, off +  bsize, 0x200);
+               if (buf == NULL)
+                       return -1;
+
+               part = (struct mac_partition *) buf;
+               if (strncmp(part->signature, "PM", 2) != 0)
+                       return -1;
+
+               part_count = be32_to_cpu(part->map_count);
+               dbg("expecting %d partition entries", part_count);
+
+               if (id->partitions != NULL)
+                       free(id->partitions);
+               id->partitions =
+                       malloc(part_count * sizeof(struct volume_id_partition));
+               if (id->partitions == NULL)
+                       return -1;
+               memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
+
+               id->partition_count = part_count;
+
+               for (i = 0; i < part_count; i++) {
+                       __u64 poff;
+                       __u64 plen;
+
+                       buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
+                       if (buf == NULL)
+                               return -1;
+
+                       part = (struct mac_partition *) buf;
+                       if (strncmp(part->signature, "PM", 2) != 0)
+                               return -1;
+
+                       poff = be32_to_cpu(part->start_block) * bsize;
+                       plen = be32_to_cpu(part->block_count) * bsize;
+                       dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
+                           part->type, poff, plen);
+
+                       id->partitions[i].off = poff;
+                       id->partitions[i].len = plen;
+
+                       if (strncmp(part->type, "Apple_Free", 10) == 0) {
+                               id->partitions[i].usage_id = VOLUME_ID_UNUSED;
+                       } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
+                               id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
+                               id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
+                       } else {
+                               id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
+                       }
+               }
+               id->usage_id = VOLUME_ID_PARTITIONTABLE;
+               id->type_id = VOLUME_ID_MACPARTMAP;
+               id->type = "mac_partition_map";
+               return 0;
+       }
+
+       return -1;
+}
+
+#define HFS_SUPERBLOCK_OFFSET          0x400
+#define HFS_NODE_LEAF                  0xff
+#define HFSPLUS_POR_CNID               1
+static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
+{
+       struct finder_info {
+               __u32   boot_folder;
+               __u32   start_app;
+               __u32   open_folder;
+               __u32   os9_folder;
+               __u32   reserved;
+               __u32   osx_folder;
+               __u8    id[8];
+       } __attribute__((__packed__));
+
+       struct hfs_mdb {
+               __u8    signature[2];
+               __u32   cr_date;
+               __u32   ls_Mod;
+               __u16   atrb;
+               __u16   nm_fls;
+               __u16   vbm_st;
+               __u16   alloc_ptr;
+               __u16   nm_al_blks;
+               __u32   al_blk_size;
+               __u32   clp_size;
+               __u16   al_bl_st;
+               __u32   nxt_cnid;
+               __u16   free_bks;
+               __u8    label_len;
+               __u8    label[27];
+               __u32   vol_bkup;
+               __u16   vol_seq_num;
+               __u32   wr_cnt;
+               __u32   xt_clump_size;
+               __u32   ct_clump_size;
+               __u16   num_root_dirs;
+               __u32   file_count;
+               __u32   dir_count;
+               struct finder_info finfo;
+               __u8    embed_sig[2];
+               __u16   embed_startblock;
+               __u16   embed_blockcount;
+       } __attribute__((__packed__)) *hfs;
+
+       struct hfsplus_bnode_descriptor {
+               __u32   next;
+               __u32   prev;
+               __u8    type;
+               __u8    height;
+               __u16   num_recs;
+               __u16   reserved;
+       } __attribute__((__packed__));
+
+       struct hfsplus_bheader_record {
+               __u16   depth;
+               __u32   root;
+               __u32   leaf_count;
+               __u32   leaf_head;
+               __u32   leaf_tail;
+               __u16   node_size;
+       } __attribute__((__packed__));
+
+       struct hfsplus_catalog_key {
+               __u16   key_len;
+               __u32   parent_id;
+               __u16   unicode_len;
+               __u8    unicode[255 * 2];
+       } __attribute__((__packed__));
+
+       struct hfsplus_extent {
+               __u32 start_block;
+               __u32 block_count;
+       } __attribute__((__packed__));
+
+       struct hfsplus_fork {
+               __u64 total_size;
+               __u32 clump_size;
+               __u32 total_blocks;
+               struct hfsplus_extent extents[8];
+       } __attribute__((__packed__));
+
+       struct hfsplus_vol_header {
+               __u8    signature[2];
+               __u16   version;
+               __u32   attributes;
+               __u32   last_mount_vers;
+               __u32   reserved;
+               __u32   create_date;
+               __u32   modify_date;
+               __u32   backup_date;
+               __u32   checked_date;
+               __u32   file_count;
+               __u32   folder_count;
+               __u32   blocksize;
+               __u32   total_blocks;
+               __u32   free_blocks;
+               __u32   next_alloc;
+               __u32   rsrc_clump_sz;
+               __u32   data_clump_sz;
+               __u32   next_cnid;
+               __u32   write_count;
+               __u64   encodings_bmp;
+               struct finder_info finfo;
+               struct hfsplus_fork alloc_file;
+               struct hfsplus_fork ext_file;
+               struct hfsplus_fork cat_file;
+               struct hfsplus_fork attr_file;
+               struct hfsplus_fork start_file;
+       } __attribute__((__packed__)) *hfsplus;
+
+       unsigned int blocksize;
+       unsigned int cat_block;
+       unsigned int cat_block_count;
+       unsigned int cat_off;
+       unsigned int cat_len;
+       unsigned int leaf_node_head;
+       unsigned int leaf_node_size;
+       unsigned int alloc_block_size;
+       unsigned int alloc_first_block;
+       unsigned int embed_first_block;
+       struct hfsplus_bnode_descriptor *descr;
+       struct hfsplus_bheader_record *bnode;
+       struct hfsplus_catalog_key *key;
+       unsigned int    label_len;
+       const __u8 *buf;
+
+       buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+       if (buf == NULL)
+                return -1;
+
+       hfs = (struct hfs_mdb *) buf;
+       if (strncmp(hfs->signature, "BD", 2) != 0)
+               goto checkplus;
+
+       /* it may be just a hfs wrapper for hfs+ */
+       if (strncmp(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", off);
+
+               buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+               if (buf == NULL)
+                       return -1;
+               goto checkplus;
+       }
+
+       if (hfs->label_len > 0 && hfs->label_len < 28) {
+               set_label_raw(id, hfs->label, hfs->label_len);
+               set_label_string(id, hfs->label, hfs->label_len) ;
+       }
+
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_HFS;
+       id->type = "hfs";
+
+       return 0;
+
+checkplus:
+       hfsplus = (struct hfsplus_vol_header *) buf;
+       if (strncmp(hfsplus->signature, "H+", 2) == 0)
+               goto hfsplus;
+       if (strncmp(hfsplus->signature, "HX", 2) == 0)
+               goto hfsplus;
+       return -1;
+
+hfsplus:
+       blocksize = be32_to_cpu(hfsplus->blocksize);
+       cat_block = be32_to_cpu(hfsplus->cat_file.extents[0].start_block);
+       cat_block_count = be32_to_cpu(hfsplus->cat_file.extents[0].block_count);
+       cat_off = (cat_block * blocksize);
+       cat_len = cat_block_count * blocksize;
+       dbg("catalog start 0x%llx, len 0x%x", off + cat_off, cat_len);
+
+       buf = get_buffer(id, off + cat_off, 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);
+       leaf_node_size = be16_to_cpu(bnode->node_size);
+
+       dbg("catalog leaf node 0x%x, size 0x%x",
+           leaf_node_head, leaf_node_size);
+
+       buf = get_buffer(id, off + cat_off + (leaf_node_head * leaf_node_size),
+                        leaf_node_size);
+       if (buf == NULL)
+               goto found;
+
+       descr = (struct hfsplus_bnode_descriptor *) buf;
+       dbg("descriptor type 0x%x", descr->type);
+       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);
+       set_label_raw(id, key->unicode, label_len);
+       set_label_unicode16(id, key->unicode, BE, label_len);
+
+found:
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_HFSPLUS;
+       id->type = "hfsplus";
 
        return 0;
 }
 
 #define MFT_RECORD_VOLUME                      3
-#define MFT_RECORD_ATTR_VOLUME_NAME            0x60u
-#define MFT_RECORD_ATTR_OBJECT_ID              0x40u
+#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
-static int probe_ntfs(struct volume_id *id)
+static int probe_ntfs(struct volume_id *id, __u64 off)
 {
        struct ntfs_super_block {
                __u8    jump[3];
                __u8    oem_id[8];
-               struct bios_param_block {
-                       __u16   bytes_per_sector;
-                       __u8    sectors_per_cluster;
-                       __u16   reserved_sectors;
-                       __u8    fats;
-                       __u16   root_entries;
-                       __u16   sectors;
-                       __u8    media_type;             /* 0xf8 = hard disk */
-                       __u16   sectors_per_fat;
-                       __u16   sectors_per_track;
-                       __u16   heads;
-                       __u32   hidden_sectors;
-                       __u32   large_sectors;
-               } __attribute__((__packed__)) bpb;
-               __u8 unused[4];
+               __u16   bytes_per_sector;
+               __u8    sectors_per_cluster;
+               __u16   reserved_sectors;
+               __u8    fats;
+               __u16   root_entries;
+               __u16   sectors;
+               __u8    media_type;
+               __u16   sectors_per_fat;
+               __u16   sectors_per_track;
+               __u16   heads;
+               __u32   hidden_sectors;
+               __u32   large_sectors;
+               __u16   unused[2];
                __u64   number_of_sectors;
                __u64   mft_cluster_location;
                __u64   mft_mirror_cluster_location;
                __s8    cluster_per_mft_record;
+               __u8    reserved1[3];
+               __s8    cluster_per_index_record;
+               __u8    reserved2[3];
+               __u8    volume_serial[8];
+               __u16   checksum;
        } __attribute__((__packed__)) *ns;
 
        struct master_file_table_record {
@@ -752,28 +1761,36 @@ static int probe_ntfs(struct volume_id *id)
                __u16   value_offset;
        } __attribute__((__packed__)) *attr;
 
-       unsigned int    sector_size;
-       unsigned int    cluster_size;
-       unsigned long   mft_cluster;
-       unsigned long   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;
+       struct volume_info {
+               __u64 reserved;
+               __u8 major_ver;
+               __u8 minor_ver;
+       } __attribute__((__packed__)) *info;
+
+       unsigned int sector_size;
+       unsigned int cluster_size;
+       __u64 mft_cluster;
+       __u64 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 __u8 *buf;
        const __u8 *val;
 
-       ns = (struct ntfs_super_block *) get_buffer(id, 0, 0x200);
+       ns = (struct ntfs_super_block *) get_buffer(id, off, 0x200);
        if (ns == NULL)
                return -1;
 
        if (strncmp(ns->oem_id, "NTFS", 4) != 0)
                return -1;
 
-       sector_size = le16_to_cpu(ns->bpb.bytes_per_sector);
-       cluster_size = ns->bpb.sectors_per_cluster * sector_size;
+       set_uuid(id, ns->volume_serial, 8);
+
+       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;
 
@@ -785,22 +1802,19 @@ static int probe_ntfs(struct volume_id *id)
 
        dbg("sectorsize  0x%x", sector_size);
        dbg("clustersize 0x%x", cluster_size);
-       dbg("mftcluster  %li", mft_cluster);
-       dbg("mftoffset  0x%lx", mft_off);
+       dbg("mftcluster  %lli", mft_cluster);
+       dbg("mftoffset  0x%llx", mft_off);
        dbg("cluster per mft_record  %i", ns->cluster_per_mft_record);
        dbg("mft record size  %i", mft_record_size);
 
-       buf = get_buffer(id, mft_off + (MFT_RECORD_VOLUME * mft_record_size),
+       buf = 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[0] = '%c' %03d, 0x%02x", mftr->magic[0], mftr->magic[0], mftr->magic[0]);
-       dbg("mftr->magic[1] = '%c' %03d, 0x%02x", mftr->magic[1], mftr->magic[1], mftr->magic[1]);
-       dbg("mftr->magic[2] = '%c' %03d, 0x%02x", mftr->magic[2], mftr->magic[2], mftr->magic[2]);
-       dbg("mftr->magic[3] = '%c' %03d, 0x%02x", mftr->magic[3], mftr->magic[3], mftr->magic[3]);
+       dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
        if (strncmp(mftr->magic, "FILE", 4) != 0)
                goto found;
 
@@ -813,6 +1827,13 @@ static int probe_ntfs(struct volume_id *id)
                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;
@@ -820,136 +1841,182 @@ static int probe_ntfs(struct volume_id *id)
                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*) (((__u8 *) attr) + val_off);
+                       snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-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 = &((__u8 *) attr)[val_off];
+                       val = ((__u8 *) attr) + val_off;
                        set_label_raw(id, val, val_len);
                        set_label_unicode16(id, val, LE, val_len);
                }
-
-               if (attr_type == MFT_RECORD_ATTR_OBJECT_ID) {
-                       dbg("found uuid");
-                       val = &((__u8 *) attr)[val_off];
-                       set_uuid(id, val, 16);
-               }
-
-               if (attr_len == 0)
-                       break;
-               attr_off += attr_len;
-               if (attr_off >= mft_record_size)
-                       break;
        }
 
 found:
-       id->fs_type = NTFS;
-       id->fs_name = "ntfs";
+       id->usage_id = VOLUME_ID_FILESYSTEM;
+       id->type_id = VOLUME_ID_NTFS;
+       id->type = "ntfs";
 
        return 0;
 }
 
 #define LARGEST_PAGESIZE                       0x4000
-static int probe_swap(struct volume_id *id)
+static int probe_swap(struct volume_id *id, __u64 off)
 {
        const __u8 *sig;
        unsigned int page;
 
        /* huhh, the swap signature is on the end of the PAGE_SIZE */
        for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
-                       sig = get_buffer(id, page-10, 10);
+                       sig = get_buffer(id, off + page-10, 10);
                        if (sig == NULL)
                                return -1;
 
-                       if (strncmp(sig, "SWAP-SPACE", 10) == 0)
+                       if (strncmp(sig, "SWAP-SPACE", 10) == 0) {
+                               strcpy(id->type_version, "1");
                                goto found;
-                       if (strncmp(sig, "SWAPSPACE2", 10) == 0)
+                       }
+                       if (strncmp(sig, "SWAPSPACE2", 10) == 0) {
+                               strcpy(id->type_version, "2");
                                goto found;
+                       }
        }
        return -1;
 
 found:
-       id->fs_type = SWAP;
-       id->fs_name = "swap";
+       id->usage_id = VOLUME_ID_OTHER;
+       id->type_id = VOLUME_ID_SWAP;
+       id->type = "swap";
 
        return 0;
 }
 
 /* probe volume for filesystem type and try to read label+uuid */
-int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type)
+int volume_id_probe(struct volume_id *id,
+                   enum volume_id_type type,
+                   unsigned long long off,
+                   unsigned long long size)
 {
        int rc;
 
        if (id == NULL)
                return -EINVAL;
 
-       switch (fs_type) {
-       case EXT3:
-       case EXT2:
-               rc = probe_ext(id);
+       switch (type) {
+       case VOLUME_ID_MSDOSPARTTABLE:
+               rc = probe_msdos_part_table(id, off);
+               break;
+       case VOLUME_ID_EXT3:
+       case VOLUME_ID_EXT2:
+               rc = probe_ext(id, off);
+               break;
+       case VOLUME_ID_REISERFS:
+               rc = probe_reiserfs(id, off);
+               break;
+       case VOLUME_ID_XFS:
+               rc = probe_xfs(id, off);
+               break;
+       case VOLUME_ID_JFS:
+               rc = probe_jfs(id, off);
+               break;
+       case VOLUME_ID_VFAT:
+               rc = probe_vfat(id, off);
                break;
-       case REISER:
-               rc = probe_reiser(id);
+       case VOLUME_ID_UDF:
+               rc = probe_udf(id, off);
                break;
-       case XFS:
-               rc = probe_xfs(id);
+       case VOLUME_ID_ISO9660:
+               rc = probe_iso9660(id, off);
                break;
-       case JFS:
-               rc = probe_jfs(id);
+       case VOLUME_ID_MACPARTMAP:
+               rc = probe_mac_partition_map(id, off);
                break;
-       case MSDOS:
-               rc = probe_msdos(id);
+       case VOLUME_ID_HFS:
+       case VOLUME_ID_HFSPLUS:
+               rc = probe_hfs_hfsplus(id, off);
                break;
-       case VFAT:
-               rc = probe_vfat(id);
+       case VOLUME_ID_UFS:
+               rc = probe_ufs(id, off);
                break;
-       case UDF:
-               rc = probe_udf(id);
+       case VOLUME_ID_NTFS:
+               rc = probe_ntfs(id, off);
                break;
-       case ISO9660:
-               rc = probe_iso9660(id);
+       case VOLUME_ID_SWAP:
+               rc = probe_swap(id, off);
                break;
-       case NTFS:
-               rc = probe_ntfs(id);
+       case VOLUME_ID_LINUX_RAID:
+               rc = probe_linux_raid(id, off, size);
                break;
-       case SWAP:
-               rc = probe_swap(id);
+       case VOLUME_ID_LVM1:
+               rc = probe_lvm1(id, off);
                break;
-       case ALL:
+       case VOLUME_ID_LVM2:
+               rc = probe_lvm2(id, off);
+               break;
+       case VOLUME_ID_ALL:
        default:
+               rc = probe_linux_raid(id, off, size);
+               if (rc == 0)
+                       break;
+
+               /* signature in the first block */
+               rc = probe_ntfs(id, off);
+               if (rc == 0)
+                       break;
+               rc = probe_vfat(id, off);
+               if (rc == 0)
+                       break;
+               rc = probe_msdos_part_table(id, off);
+               if (rc == 0)
+                       break;
+               rc = probe_mac_partition_map(id, off);
+               if (rc == 0)
+                       break;
+               rc = probe_xfs(id, off);
+               if (rc == 0)
+                       break;
+
                /* fill buffer with maximum */
                get_buffer(id, 0, SB_BUFFER_SIZE);
-               rc = probe_ext(id);
+
+               rc = probe_swap(id, off);
                if (rc == 0)
                        break;
-               rc = probe_reiser(id);
+               rc = probe_ext(id, off);
                if (rc == 0)
                        break;
-               rc = probe_xfs(id);
+               rc = probe_reiserfs(id, off);
                if (rc == 0)
                        break;
-               rc = probe_jfs(id);
+               rc = probe_jfs(id, off);
                if (rc == 0)
                        break;
-               rc = probe_msdos(id);
+               rc = probe_udf(id, off);
                if (rc == 0)
                        break;
-               rc = probe_vfat(id);
+               rc = probe_iso9660(id, off);
                if (rc == 0)
                        break;
-               rc = probe_udf(id);
+               rc = probe_hfs_hfsplus(id, off);
                if (rc == 0)
                        break;
-               rc = probe_iso9660(id);
+               rc = probe_ufs(id, off);
                if (rc == 0)
                        break;
-               rc = probe_ntfs(id);
+               rc = probe_lvm1(id, off);
                if (rc == 0)
                        break;
-               rc = probe_swap(id);
+               rc = probe_lvm2(id, off);
                if (rc == 0)
                        break;
+
                rc = -1;
        }
 
@@ -982,9 +2049,11 @@ struct volume_id *volume_id_open_node(const char *path)
        struct volume_id *id;
        int fd;
 
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
+       fd = open(path, O_RDONLY | O_NONBLOCK);
+       if (fd < 0) {
+               dbg("unable to open '%s'", path);
                return NULL;
+       }
 
        id = volume_id_open_fd(fd);
        if (id == NULL)
@@ -1029,5 +2098,8 @@ void volume_id_close(struct volume_id *id)
 
        free_buffer(id);
 
+       if (id->partitions != NULL)
+               free(id->partitions);
+
        free(id);
 }
index a939743..eb90390 100644 (file)
 #ifndef _VOLUME_ID_H_
 #define _VOLUME_ID_H_
 
-#define VOLUME_ID_VERSION              004
+#define VOLUME_ID_VERSION              022
 
 #define VOLUME_ID_LABEL_SIZE           64
 #define VOLUME_ID_UUID_SIZE            16
 #define VOLUME_ID_UUID_STRING_SIZE     37
-#define VOLUME_ID_PATH_MAX             255
+#define VOLUME_ID_FORMAT_SIZE          32
+#define VOLUME_ID_PATH_MAX             256
+#define VOLUME_ID_PARTITIONS_MAX       16
 
+enum volume_id_usage {
+       VOLUME_ID_UNUSED,
+       VOLUME_ID_UNPROBED,
+       VOLUME_ID_OTHER,
+       VOLUME_ID_FILESYSTEM,
+       VOLUME_ID_PARTITIONTABLE,
+       VOLUME_ID_RAID
+};
+
+enum volume_id_type {
+       VOLUME_ID_ALL,
+       VOLUME_ID_MSDOSPARTTABLE,
+       VOLUME_ID_MSDOSEXTENDED,
+       VOLUME_ID_SWAP,
+       VOLUME_ID_EXT2,
+       VOLUME_ID_EXT3,
+       VOLUME_ID_REISERFS,
+       VOLUME_ID_XFS,
+       VOLUME_ID_JFS,
+       VOLUME_ID_VFAT,
+       VOLUME_ID_UDF,
+       VOLUME_ID_ISO9660,
+       VOLUME_ID_NTFS,
+       VOLUME_ID_MACPARTMAP,
+       VOLUME_ID_HFS,
+       VOLUME_ID_HFSPLUS,
+       VOLUME_ID_UFS,
+       VOLUME_ID_LINUX_RAID,
+       VOLUME_ID_LVM1,
+       VOLUME_ID_LVM2
+};
 
-enum filesystem_type {
-       ALL,
-       EXT2,
-       EXT3,
-       REISER,
-       XFS,
-       JFS,
-       MSDOS,
-       VFAT,
-       UDF,
-       ISO9660,
-       NTFS,
-       SWAP
+struct volume_id_partition {
+       enum            volume_id_usage usage_id;
+       enum            volume_id_type type_id;
+       char            *type;
+       unsigned long long off;
+       unsigned long long len;
 };
 
 struct volume_id {
        unsigned char   label_raw[VOLUME_ID_LABEL_SIZE];
        unsigned int    label_raw_len;
-       char            label_string[VOLUME_ID_LABEL_SIZE+1];
-       unsigned char   uuid[VOLUME_ID_UUID_SIZE];
-       char            uuid_string[VOLUME_ID_UUID_STRING_SIZE];
-       enum            filesystem_type fs_type;
-       char            *fs_name;
+       char            label[VOLUME_ID_LABEL_SIZE+1];
+       unsigned char   uuid_raw[VOLUME_ID_UUID_SIZE];
+       char            uuid[VOLUME_ID_UUID_STRING_SIZE];
+       enum            volume_id_usage usage_id;
+       enum            volume_id_type type_id;
+       char            *type;
+       char            type_version[VOLUME_ID_FORMAT_SIZE];
+       struct volume_id_partition *partitions;
+       unsigned int    partition_count;
        int             fd;
        unsigned char   *sbbuf;
        unsigned int    sbbuf_len;
        unsigned char   *seekbuf;
-       unsigned int    seekbuf_off;
+       unsigned long long seekbuf_off;
        unsigned int    seekbuf_len;
        int             fd_close;
 };
@@ -71,7 +101,8 @@ extern struct volume_id *volume_id_open_node(const char *path);
 extern struct volume_id *volume_id_open_dev_t(dev_t devt);
 
 /* probe volume for filesystem type and try to read label/uuid */
-extern int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type);
+extern int volume_id_probe(struct volume_id *id, enum volume_id_type type,
+                          unsigned long long off, unsigned long long size);
 
 /* free allocated device info */
 extern void volume_id_close(struct volume_id *id);