summaryrefslogtreecommitdiff
path: root/sys-boot/grub/files/grub-0.97-uuid.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sys-boot/grub/files/grub-0.97-uuid.patch')
-rw-r--r--sys-boot/grub/files/grub-0.97-uuid.patch5406
1 files changed, 5406 insertions, 0 deletions
diff --git a/sys-boot/grub/files/grub-0.97-uuid.patch b/sys-boot/grub/files/grub-0.97-uuid.patch
new file mode 100644
index 00000000..f99670a8
--- /dev/null
+++ b/sys-boot/grub/files/grub-0.97-uuid.patch
@@ -0,0 +1,5406 @@
+=== modified file 'Makefile.am'
+--- grub-0.97.orig/Makefile.am 2004-04-23 13:39:01 +0000
++++ grub-0.97/Makefile.am 2008-07-09 17:23:44 +0000
+@@ -1,4 +1,9 @@
+ # Do not change this order if you don't know what you are doing.
+ AUTOMAKE_OPTIONS = 1.7 gnu
+-SUBDIRS = netboot stage2 stage1 lib grub util docs
++if UUID_SUPPORT
++SUBDIRS = libvolume_id netboot stage2 stage1 lib grub util docs
++else
++SUBDIRS = netboot stage2 stage1 lib grub util docs
++endif
++
+ EXTRA_DIST = BUGS MAINTENANCE
+
+=== modified file 'configure.ac'
+--- grub-0.97.orig/configure.ac 2008-01-28 18:41:45 +0000
++++ grub-0.97/configure.ac 2008-07-09 17:23:44 +0000
+@@ -605,6 +606,11 @@
+ [ --disable-serial disable serial terminal support])
+ AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno)
+
++dnl UUID scanning
++AC_ARG_ENABLE(uuid,
++ [ --disable-uuid disable uuid scanning support])
++AM_CONDITIONAL(UUID_SUPPORT, test "x$enable_uuid" != xno)
++
+ dnl Simulation of the slowness of a serial device.
+ AC_ARG_ENABLE(serial-speed-simulation,
+ [ --enable-serial-speed-simulation
+@@ -666,5 +672,6 @@
+ docs/Makefile lib/Makefile util/Makefile \
+ grub/Makefile netboot/Makefile util/grub-image \
+ util/grub-install util/grub-md5-crypt \
+- util/grub-terminfo util/grub-set-default])
++ util/grub-terminfo util/grub-set-default \
++ libvolume_id/Makefile])
+ AC_OUTPUT
+
+=== modified file 'grub/Makefile.am'
+--- grub-0.97.orig/grub/Makefile.am 2005-02-02 20:40:05 +0000
++++ grub-0.97/grub/Makefile.am 2008-07-09 17:23:44 +0000
+@@ -16,4 +16,9 @@
+ AM_CFLAGS = $(GRUB_CFLAGS)
+
+ grub_SOURCES = main.c asmstub.c
+-grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
++
++if UUID_SUPPORT
++grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a ../libvolume_id/libvolume_id.a $(GRUB_LIBS)
++else
++grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
++endif
+
+=== added directory 'libvolume_id'
+=== added file 'libvolume_id/Makefile.am'
+--- grub-0.97.orig/libvolume_id/Makefile.am 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/Makefile.am 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,27 @@
++noinst_LIBRARIES = libvolume_id.a
++
++AM_CFLAGS = $(STAGE2_CFLAGS) -I$(top_srcdir)/stage2 -I$(top_srcdir)/stage1
++
++LIBVOLUME_ID_FS_SUPPORTED = ext.c fat.c hfs.c jfs.c \
++ luks.c ntfs.c ocfs.c reiserfs.c \
++ xfs.c
++
++LIBVOLUME_ID_FS_UNSUPPORTED = cramfs.c gfs.c hpfs.c iso9660.c \
++ lvm.c minix.c romfs.c squashfs.c \
++ sysv.c udf.c ufs.c vxfs.c
++
++LIBVOLUME_ID_RAID_SUPPORTED = ddf_raid.c
++
++LIBVOLUME_ID_RAID_UNSUPPORTED = adaptec_raid.c highpoint.c isw_raid.c \
++ jmicron_raid.c linux_raid.c lsi_raid.c \
++ nvidia_raid.c promise_raid.c silicon_raid.c \
++ via_raid.c
++
++LIBVOLUME_ID_MISC_UNSUPPORTED = linux_swap.c netware.c
++
++libvolume_id_a_SOURCES = $(LIBVOLUME_ID_FS_SUPPORTED) \
++ $(LIBVOLUME_ID_RAID_SUPPORTED) \
++ $(LIBVOLUME_ID_FS_UNSUPPORTED) \
++ $(LIBVOLUME_ID_RAID_UNSUPPORTED) \
++ volume_id.h volume_id.c util.c util.h misc.c
++
+
+=== added file 'libvolume_id/adaptec_raid.c'
+--- grub-0.97.orig/libvolume_id/adaptec_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/adaptec_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,107 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct adaptec_meta {
++ uint32_t b0idcode;
++ uint8_t lunsave[8];
++ uint16_t sdtype;
++ uint16_t ssavecyl;
++ uint8_t ssavehed;
++ uint8_t ssavesec;
++ uint8_t sb0flags;
++ uint8_t jbodEnable;
++ uint8_t lundsave;
++ uint8_t svpdirty;
++ uint16_t biosInfo;
++ uint16_t svwbskip;
++ uint16_t svwbcln;
++ uint16_t svwbmax;
++ uint16_t res3;
++ uint16_t svwbmin;
++ uint16_t res4;
++ uint16_t svrcacth;
++ uint16_t svwcacth;
++ uint16_t svwbdly;
++ uint8_t svsdtime;
++ uint8_t res5;
++ uint16_t firmval;
++ uint16_t firmbln;
++ uint32_t firmblk;
++ uint32_t fstrsvrb;
++ uint16_t svBlockStorageTid;
++ uint16_t svtid;
++ uint8_t svseccfl;
++ uint8_t res6;
++ uint8_t svhbanum;
++ uint8_t resver;
++ uint32_t drivemagic;
++ uint8_t reserved[20];
++ uint8_t testnum;
++ uint8_t testflags;
++ uint16_t maxErrorCount;
++ uint32_t count;
++ uint32_t startTime;
++ uint32_t interval;
++ uint8_t tstxt0;
++ uint8_t tstxt1;
++ uint8_t serNum[32];
++ uint8_t res8[102];
++ uint32_t fwTestMagic;
++ uint32_t fwTestSeqNum;
++ uint8_t fwTestRes[8];
++ uint8_t smagic[4];
++ uint32_t raidtbl;
++ uint16_t raidline;
++ uint8_t res9[0xF6];
++} PACKED;
++
++int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct adaptec_meta *ad;
++
++ info("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;
++
++ ad = (struct adaptec_meta *) buf;
++ if (memcmp((char*)ad->smagic, "DPTM", 4) != 0)
++ return -1;
++
++ if (ad->b0idcode != be32_to_cpu(0x37FC4D1E))
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u", ad->resver);
++ id->type = "adaptec_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/cramfs.c'
+--- grub-0.97.orig/libvolume_id/cramfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/cramfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,60 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct cramfs_super *cs;
++
++ info("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((char*)cs->magic, "\x45\x3d\xcd\x28", 4) == 0 || memcmp((char*)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;
++}
+
+=== added file 'libvolume_id/ddf_raid.c'
+--- grub-0.97.orig/libvolume_id/ddf_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ddf_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,60 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++/* http://www.snia.org/standards/home */
++
++#define DDF_HEADER 0xDE11DE11
++#define DDF_GUID_LENGTH 24
++#define DDF_REV_LENGTH 8
++
++static struct ddf_header {
++ uint32_t signature;
++ uint32_t crc;
++ uint8_t guid[DDF_GUID_LENGTH];
++ uint8_t ddf_rev[DDF_REV_LENGTH];
++} PACKED *ddf;
++
++int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint64_t ddf_off = ((size / 0x200)-1) * 0x200;
++ const uint8_t *buf;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++ if (size < 0x10000)
++ return -1;
++
++ buf = volume_id_get_buffer(id, off + ddf_off, 0x200);
++ if (buf == NULL)
++ return -1;
++ ddf = (struct ddf_header *) buf;
++
++ if (ddf->signature != cpu_to_be32(DDF_HEADER))
++ return -1;
++
++ volume_id_set_uuid(id, ddf->guid, DDF_GUID_LENGTH, UUID_STRING);
++ strcpy(id->type_version, (char*) ddf->ddf_rev);
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "ddf_raid_member";
++ return 0;
++}
+
+=== added file 'libvolume_id/ext.c'
+--- grub-0.97.orig/libvolume_id/ext.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ext.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,129 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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 0x0004
++#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
++#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
++#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
++#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
++
++#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, uint64_t size)
++{
++ struct ext2_super_block *es;
++ size_t bsize;
++ uint32_t feature_compat;
++ uint32_t feature_incompat;
++
++ info("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, 0, UUID_DCE);
++ sprintf(id->type_version, "%u.%u",
++ le32_to_cpu(es->s_rev_level), le16_to_cpu(es->s_minor_rev_level));
++
++ feature_compat = le32_to_cpu(es->s_feature_compat);
++ feature_incompat = le32_to_cpu(es->s_feature_incompat);
++
++ /* check for external journal device */
++ if ((feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) != 0) {
++ volume_id_set_usage(id, VOLUME_ID_OTHER);
++ id->type = "jbd";
++ goto out;
++ }
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++
++ if ((feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) != 0 ||
++ (feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0 ||
++ (feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) != 0) {
++ id->type = "ext4";
++ goto out;
++ }
++
++ if ((feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
++ id->type = "ext3";
++ goto out;
++ }
++
++ id->type = "ext2";
++
++out:
++ return 0;
++}
+
+=== added file 'libvolume_id/fat.c'
+--- grub-0.97.orig/libvolume_id/fat.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/fat.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,482 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Copyright (C) 2007 Ryan Lortie <desrt@desrt.ca>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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
++
++#define VFAT_LFN_SEQ_MASK 0x3f
++#define VFAT_LFN_SEQ_LAST 0x40
++#define VFAT_LFN_SEQ_MAX 20
++#define VFAT_LFN_CHARS_PER_ENTRY (5 + 6 + 2)
++#define VFAT_LOWERCASE_NAME 0x10
++#define VFAT_LOWERCASE_EXT 0x08
++
++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 fsinfo_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 fat32_fsinfo {
++ uint8_t signature1[4];
++ uint32_t reserved1[120];
++ uint8_t signature2[4];
++ uint32_t free_clusters;
++ uint32_t next_cluster;
++ uint32_t reserved2[4];
++} PACKED;
++
++struct vfat_dir_entry {
++ uint8_t name[11];
++ uint8_t attr;
++ uint8_t lowercase;
++ uint8_t fine_time_creat;
++ uint16_t time_creat;
++ uint16_t date_creat;
++ uint16_t date_acc;
++ uint16_t cluster_high;
++ uint16_t time_write;
++ uint16_t date_write;
++ uint16_t cluster_low;
++ uint32_t size;
++} PACKED;
++
++
++struct vfat_lfn_entry {
++ uint8_t seq;
++ uint16_t name0[5];
++ uint8_t attr;
++ uint8_t reserved;
++ uint8_t cksum;
++ uint16_t name1[6];
++ uint16_t cluster;
++ uint16_t name2[2];
++} PACKED;
++
++static uint8_t fat_lfn_checksum(const uint8_t name[11])
++{
++ uint8_t cksum = 0;
++ int i;
++
++ /* http://en.wikipedia.org/wiki/File_Allocation_Table */
++ for (i = 0; i < 11; i++)
++ cksum = ((cksum & 1) ? 0x80 : 0) + (cksum >> 1) + name[i];
++
++ return cksum;
++}
++
++static size_t fat_read_lfn(uint8_t *filename, size_t fnsize,
++ struct vfat_dir_entry *direntry,
++ struct vfat_dir_entry *entry)
++{
++ uint8_t buffer[VFAT_LFN_SEQ_MAX * VFAT_LFN_CHARS_PER_ENTRY * 2];
++ uint8_t expected_seq = 1;
++ uint8_t cksum;
++ size_t len = 0;
++ size_t fnlen = 0;
++
++ cksum = fat_lfn_checksum(entry->name);
++
++ while (--entry >= direntry) {
++ struct vfat_lfn_entry *lfn = (struct vfat_lfn_entry *) entry;
++
++ if (expected_seq > VFAT_LFN_SEQ_MAX)
++ break;
++
++ if ((lfn->attr & FAT_ATTR_MASK) != FAT_ATTR_LONG_NAME)
++ break;
++
++ if (lfn->cksum != cksum)
++ break;
++
++ if ((lfn->seq & VFAT_LFN_SEQ_MASK) != expected_seq++)
++ break;
++
++ if (lfn->cluster != 0)
++ break;
++
++ /* extra paranoia -- should never happen */
++ if (len + sizeof(lfn->name0) + sizeof(lfn->name1) +
++ sizeof(lfn->name2) > sizeof(buffer))
++ break;
++
++ memcpy (&buffer[len], lfn->name0, sizeof(lfn->name0));
++ len += sizeof(lfn->name0);
++ memcpy (&buffer[len], lfn->name1, sizeof(lfn->name1));
++ len += sizeof(lfn->name1);
++ memcpy (&buffer[len], lfn->name2, sizeof(lfn->name2));
++ len += sizeof(lfn->name2);
++
++ if (lfn->seq & VFAT_LFN_SEQ_LAST) {
++ fnlen = volume_id_set_unicode16(filename, fnsize, buffer, LE, len);
++ break;
++ }
++ }
++
++ return fnlen;
++}
++
++static size_t fat_read_filename(uint8_t *filename, size_t fnsize,
++ struct vfat_dir_entry *direntry, struct vfat_dir_entry *entry)
++{
++ size_t len;
++ int i;
++
++ /* check if maybe we have LFN entries */
++ len = fat_read_lfn(filename, fnsize, direntry, entry);
++ if (len > 0)
++ goto out;
++
++ /* else, read the normal 8.3 name */
++ for (i = 0; i < 11; i++) {
++ if (entry->lowercase & ((i < 8) ? VFAT_LOWERCASE_NAME : VFAT_LOWERCASE_EXT))
++ filename[i] = tolower(entry->name[i]);
++ else
++ filename[i] = entry->name[i];
++ }
++ len = 11;
++
++out:
++ filename[len] = '\0';
++ return len;
++}
++
++/* fills filename, returns string length */
++static size_t get_fat_attr_volume_id(uint8_t *filename, size_t fnsize,
++ struct vfat_dir_entry *direntry, unsigned int count)
++{
++ unsigned int i;
++
++ for (i = 0; i < count; i++) {
++ /* end marker */
++ if (direntry[i].name[0] == 0x00) {
++ dbg("end of dir");
++ break;
++ }
++
++ /* empty entry */
++ if (direntry[i].name[0] == FAT_ENTRY_FREE)
++ continue;
++
++ /* long name */
++ if ((direntry[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
++ continue;
++
++ if ((direntry[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
++ /* labels do not have file data */
++ if (direntry[i].cluster_high != 0 || direntry[i].cluster_low != 0)
++ continue;
++
++ dbg("found ATTR_VOLUME_ID id in root dir");
++ return fat_read_filename(filename, fnsize, direntry, &direntry[i]);
++ }
++
++ dbg("skip dir entry");
++ }
++
++ return 0;
++}
++
++int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint8_t filename[255 * 3];
++ struct vfat_super_block *vs;
++ struct vfat_dir_entry *direntry;
++ struct fat32_fsinfo *fsinfo;
++ 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;
++ uint16_t fsinfo_sect;
++ uint8_t *buf;
++ uint32_t buf_size;
++ uint32_t next;
++ int maxloop;
++ size_t fnlen;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off, 0x400);
++ if (buf == NULL)
++ return -1;
++
++ /* check signature */
++ if (buf[510] != 0x55 || buf[511] != 0xaa)
++ return -1;
++
++ vs = (struct vfat_super_block *) buf;
++ if (memcmp((char*)vs->sysid, "NTFS", 4) == 0)
++ return -1;
++
++ /* believe only that's fat, don't trust the version */
++ if (memcmp((char*)vs->type.fat32.magic, "MSWIN", 5) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat32.magic, "FAT32 ", 8) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat.magic, "FAT16 ", 8) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat.magic, "MSDOS", 5) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat.magic, "FAT12 ", 8) == 0)
++ goto magic;
++
++ /* some old floppies don't have a magic, expect the boot jump address to match */
++ 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 == 0 || ((sector_size & (sector_size-1)) != 0))
++ 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;
++
++ direntry = (struct vfat_dir_entry*) buf;
++
++ fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, root_dir_entries);
++
++ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
++ if (vs == NULL)
++ return -1;
++
++ if (fnlen > 0 && memcmp((char*)filename, "NO NAME ", 11) != 0) {
++ volume_id_set_label_raw(id, filename, fnlen);
++ volume_id_set_label_string(id, filename, fnlen);
++ } else if (memcmp((char*)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, 0, UUID_DOS);
++ goto found;
++
++fat32:
++ /* FAT32 should have a valid signature in the fsinfo block */
++ fsinfo_sect = le16_to_cpu(vs->type.fat32.fsinfo_sector);
++ buf = volume_id_get_buffer(id, off + (fsinfo_sect * sector_size), 0x200);
++ if (buf == NULL)
++ return -1;
++ fsinfo = (struct fat32_fsinfo *) buf;
++ if (memcmp((char*)fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0)
++ return -1;
++ if (memcmp((char*)fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0)
++ return -1 ;
++
++ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
++ if (vs == NULL)
++ return -1;
++
++ 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;
++
++ direntry = (struct vfat_dir_entry*) buf;
++ count = buf_size / sizeof(struct vfat_dir_entry);
++ dbg("expected entries 0x%x", count);
++
++ fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, count);
++ if (fnlen > 0)
++ 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 < 2 || next >= 0x0ffffff0)
++ 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 (fnlen > 0 && memcmp((char*)filename, "NO NAME ", 11) != 0) {
++ volume_id_set_label_raw(id, filename, fnlen);
++ volume_id_set_label_string(id, filename, fnlen);
++ } else if (memcmp((char*)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, 0, UUID_DOS);
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "vfat";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/gfs.c'
+--- grub-0.97.orig/libvolume_id/gfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/gfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,115 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Red Hat, Inc. <redhat.com>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++/* Common gfs/gfs2 constants: */
++#define GFS_MAGIC 0x01161970
++#define GFS_DEFAULT_BSIZE 4096
++#define GFS_SUPERBLOCK_OFFSET (0x10 * GFS_DEFAULT_BSIZE)
++#define GFS_METATYPE_SB 1
++#define GFS_FORMAT_SB 100
++#define GFS_LOCKNAME_LEN 64
++
++/* gfs1 constants: */
++#define GFS_FORMAT_FS 1309
++#define GFS_FORMAT_MULTI 1401
++/* gfs2 constants: */
++#define GFS2_FORMAT_FS 1801
++#define GFS2_FORMAT_MULTI 1900
++
++struct gfs2_meta_header {
++ uint32_t mh_magic;
++ uint32_t mh_type;
++ uint64_t __pad0; /* Was generation number in gfs1 */
++ uint32_t mh_format;
++ uint32_t __pad1; /* Was incarnation number in gfs1 */
++};
++
++struct gfs2_inum {
++ uint64_t no_formal_ino;
++ uint64_t no_addr;
++};
++
++struct gfs2_sb {
++ struct gfs2_meta_header sb_header;
++
++ uint32_t sb_fs_format;
++ uint32_t sb_multihost_format;
++ uint32_t __pad0; /* Was superblock flags in gfs1 */
++
++ uint32_t sb_bsize;
++ uint32_t sb_bsize_shift;
++ uint32_t __pad1; /* Was journal segment size in gfs1 */
++
++ struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
++ struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
++ struct gfs2_inum sb_root_dir;
++
++ char sb_lockproto[GFS_LOCKNAME_LEN];
++ char sb_locktable[GFS_LOCKNAME_LEN];
++ /* In gfs1, quota and license dinodes followed */
++} PACKED;
++
++static int volume_id_probe_gfs_generic(struct volume_id *id, uint64_t off, int vers)
++{
++ struct gfs2_sb *sbd;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ sbd = (struct gfs2_sb *)
++ volume_id_get_buffer(id, off + GFS_SUPERBLOCK_OFFSET, sizeof(struct gfs2_sb));
++ if (sbd == NULL)
++ return -1;
++
++ if (be32_to_cpu(sbd->sb_header.mh_magic) == GFS_MAGIC &&
++ be32_to_cpu(sbd->sb_header.mh_type) == GFS_METATYPE_SB &&
++ be32_to_cpu(sbd->sb_header.mh_format) == GFS_FORMAT_SB) {
++ if (vers == 1) {
++ if (be32_to_cpu(sbd->sb_fs_format) != GFS_FORMAT_FS ||
++ be32_to_cpu(sbd->sb_multihost_format) != GFS_FORMAT_MULTI)
++ return -1; /* not gfs1 */
++ id->type = "gfs";
++ }
++ else if (vers == 2) {
++ if (be32_to_cpu(sbd->sb_fs_format) != GFS2_FORMAT_FS ||
++ be32_to_cpu(sbd->sb_multihost_format) != GFS2_FORMAT_MULTI)
++ return -1; /* not gfs2 */
++ id->type = "gfs2";
++ }
++ else
++ return -1;
++ strcpy(id->type_version, "1");
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ return 0;
++ }
++ return -1;
++}
++
++int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ return volume_id_probe_gfs_generic(id, off, 1);
++}
++
++int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ return volume_id_probe_gfs_generic(id, off, 2);
++}
+
+=== added file 'libvolume_id/hfs.c'
+--- grub-0.97.orig/libvolume_id/hfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/hfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,318 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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;
++
++static 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;
++
++static 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
++
++static void hfsid_set_uuid(struct volume_id *id, const uint8_t *hfs_id)
++{
++#if 0
++ MD5_CTX md5c;
++ static const uint8_t hash_init[16] = {
++ 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
++ 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
++ };
++ uint8_t uuid[16];
++
++ if (*((uint64_t *)hfs_id) == 0)
++ return;
++
++ MD5_Init(&md5c);
++ MD5_Update(&md5c, &hash_init, 16);
++ MD5_Update(&md5c, hfs_id, 8);
++ MD5_Final(uuid, &md5c);
++
++ uuid[6] = 0x30 | (uuid[6] & 0x0f);
++ uuid[8] = 0x80 | (uuid[8] & 0x3f);
++ volume_id_set_uuid(id, uuid, UUID_DCE);
++#endif
++
++ volume_id_set_uuid(id, hfs_id, 0, UUID_64BIT_BE);
++}
++
++int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ 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;
++
++ info("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((char *)hfs->signature, "BD", 2) != 0)
++ goto checkplus;
++
++ /* it may be just a hfs wrapper for hfs+ */
++ if (memcmp((char *)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) ;
++ }
++
++ hfsid_set_uuid(id, hfs->finder_info.id);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "hfs";
++
++ return 0;
++
++checkplus:
++ hfsplus = (struct hfsplus_vol_header *) buf;
++ if (memcmp((char *)hfsplus->signature, "H+", 2) == 0)
++ goto hfsplus;
++ if (memcmp((char *)hfsplus->signature, "HX", 2) == 0)
++ goto hfsplus;
++ return -1;
++
++hfsplus:
++ hfsid_set_uuid(id, hfsplus->finder_info.id);
++
++ 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;
++}
+
+=== added file 'libvolume_id/highpoint.c'
+--- grub-0.97.orig/libvolume_id/highpoint.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/highpoint.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,91 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ const uint8_t *buf;
++ struct hpt37x_meta *hpt;
++ uint32_t magic;
++
++ info("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;
++}
+
+=== added file 'libvolume_id/hpfs.c'
+--- grub-0.97.orig/libvolume_id/hpfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/hpfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,51 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct hpfs_super *hs;
++
++ info("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((char *)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;
++}
+
+=== added file 'libvolume_id/iso9660.c'
+--- grub-0.97.orig/libvolume_id/iso9660.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/iso9660.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,119 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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 type;
++ uint8_t id[5];
++ uint8_t 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[5];
++ uint8_t version;
++} PACKED;
++
++int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint8_t *buf;
++ struct iso_volume_descriptor *is;
++ struct high_sierra_volume_descriptor *hs;
++
++ info("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((char*)is->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->type == ISO_VD_END)
++ break;
++ if (is->type != ISO_VD_SUPPLEMENTARY)
++ continue;
++
++ dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset));
++ if (memcmp((char *)is->escape_sequences, "%/@", 3) == 0||
++ memcmp((char *)is->escape_sequences, "%/C", 3) == 0||
++ memcmp((char *)is->escape_sequences, "%/E", 3) == 0) {
++ dbg("Joliet extension found");
++ volume_id_set_unicode16(svd_label, sizeof(svd_label), is->volume_id, BE, 32);
++ if (memcmp((char *)id->label, (char *)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((char *)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;
++}
+
+=== added file 'libvolume_id/isw_raid.c'
+--- grub-0.97.orig/libvolume_id/isw_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/isw_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,61 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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;
++
++ info("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((char *)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;
++}
+
+=== added file 'libvolume_id/jfs.c'
+--- grub-0.97.orig/libvolume_id/jfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/jfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,60 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct jfs_super_block *js;
++
++ info("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((char *)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, 0, UUID_DCE);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "jfs";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/jmicron_raid.c'
+--- grub-0.97.orig/libvolume_id/jmicron_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/jmicron_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,57 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct jmicron_meta {
++ int8_t signature[2];
++ uint8_t minor_version;
++ uint8_t major_version;
++ uint16_t checksum;
++} PACKED;
++
++int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct jmicron_meta *jm;
++
++ info("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;
++
++ jm = (struct jmicron_meta *) buf;
++ if (memcmp((char *)jm->signature, "JM", 2) != 0)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u.%u", jm->major_version, jm->minor_version);
++ id->type = "jmicron_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/linux_raid.c'
+--- grub-0.97.orig/libvolume_id/linux_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/linux_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,160 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++static struct mdp0_super_block {
++ uint32_t md_magic;
++ uint32_t major_version;
++ uint32_t minor_version;
++ uint32_t patch_version;
++ uint32_t gvalid_words;
++ uint32_t set_uuid0;
++ uint32_t ctime;
++ uint32_t level;
++ uint32_t size;
++ uint32_t nr_disks;
++ uint32_t raid_disks;
++ uint32_t md_minor;
++ uint32_t not_persistent;
++ uint32_t set_uuid1;
++ uint32_t set_uuid2;
++ uint32_t set_uuid3;
++} PACKED *mdp0;
++
++struct mdp1_super_block {
++ uint32_t magic;
++ uint32_t major_version;
++ uint32_t feature_map;
++ uint32_t pad0;
++ uint8_t set_uuid[16];
++ uint8_t set_name[32];
++} PACKED *mdp1;
++
++#define MD_RESERVED_BYTES 0x10000
++#define MD_SB_MAGIC 0xa92b4efc
++
++static int volume_id_probe_linux_raid0(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ union {
++ uint32_t ints[4];
++ uint8_t bytes[16];
++ } uuid;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++ if (size < 0x10000)
++ return -1;
++
++ buf = volume_id_get_buffer(id, off, 0x800);
++ if (buf == NULL)
++ return -1;
++ mdp0 = (struct mdp0_super_block *) buf;
++
++ if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
++ uuid.ints[0] = bswap_32(mdp0->set_uuid0);
++ if (le32_to_cpu(mdp0->minor_version >= 90)) {
++ uuid.ints[1] = bswap_32(mdp0->set_uuid1);
++ uuid.ints[2] = bswap_32(mdp0->set_uuid2);
++ uuid.ints[3] = bswap_32(mdp0->set_uuid3);
++ } else {
++ uuid.ints[1] = 0;
++ uuid.ints[2] = 0;
++ uuid.ints[3] = 0;
++ }
++ volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT);
++ sprintf(id->type_version, "%u.%u.%u",
++ le32_to_cpu(mdp0->major_version),
++ le32_to_cpu(mdp0->minor_version),
++ le32_to_cpu(mdp0->patch_version));
++ } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
++ uuid.ints[0] = mdp0->set_uuid0;
++ if (be32_to_cpu(mdp0->minor_version >= 90)) {
++ uuid.ints[1] = mdp0->set_uuid1;
++ uuid.ints[2] = mdp0->set_uuid2;
++ uuid.ints[3] = mdp0->set_uuid3;
++ } else {
++ uuid.ints[1] = 0;
++ uuid.ints[2] = 0;
++ uuid.ints[3] = 0;
++ }
++ volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT);
++ sprintf(id->type_version, "%u.%u.%u",
++ be32_to_cpu(mdp0->major_version),
++ be32_to_cpu(mdp0->minor_version),
++ be32_to_cpu(mdp0->patch_version));
++ } else
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "linux_raid_member";
++ return 0;
++}
++
++static int volume_id_probe_linux_raid1(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ buf = volume_id_get_buffer(id, off, 0x800);
++ if (buf == NULL)
++ return -1;
++ mdp1 = (struct mdp1_super_block *) buf;
++
++ if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
++ return -1;
++
++ volume_id_set_uuid(id, mdp1->set_uuid, 0, UUID_FOURINT);
++ volume_id_set_label_raw(id, mdp1->set_name, 32);
++ volume_id_set_label_string(id, mdp1->set_name, 32);
++ sprintf(id->type_version, "%u", le32_to_cpu(mdp1->major_version));
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "linux_raid_member";
++ return 0;
++}
++
++int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint64_t sboff;
++
++ /* version 0 at the end of the device */
++ sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
++ if (volume_id_probe_linux_raid0(id, off + sboff, size) == 0)
++ return 0;
++
++ /* version 1.0 at the end of the device */
++ sboff = (size & ~(0x1000 - 1)) - 0x2000;
++ if (volume_id_probe_linux_raid1(id, off + sboff, size) == 0)
++ return 0;
++
++ /* version 1.1 at the start of the device */
++ if (volume_id_probe_linux_raid1(id, off, size) == 0)
++ return 0;
++
++ /* version 1.2 at 4k offset from the start */
++ if (volume_id_probe_linux_raid1(id, off + 0x1000, size) == 0)
++ return 0;
++
++ return -1;
++}
+
+=== added file 'libvolume_id/linux_swap.c'
+--- grub-0.97.orig/libvolume_id/linux_swap.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/linux_swap.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,85 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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;
++
++#define LARGEST_PAGESIZE 0x4000
++
++int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ unsigned int page;
++ struct swap_header_v1_2 *sw;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ /* eek, 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((char *)buf, "SWAP-SPACE", 10) == 0) {
++ strcpy(id->type_version, "1");
++ goto found;
++ }
++
++ if (memcmp((char *)buf, "SWAPSPACE2", 10) == 0) {
++ id->type = "swap";
++ strcpy(id->type_version, "2");
++ goto found_label;
++ }
++
++ if (memcmp((char *)buf, "S1SUSPEND", 9) == 0) {
++ id->type = "suspend";
++ strcpy(id->type_version, "s1suspend");
++ goto found_label;
++ }
++
++ if (memcmp((char *)buf, "ULSUSPEND", 9) == 0) {
++ id->type = "suspend";
++ strcpy(id->type_version, "ulsuspend");
++ goto found_label;
++ }
++ }
++ return -1;
++
++found_label:
++ sw = (struct swap_header_v1_2 *) volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2));
++ if (sw != NULL) {
++ 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, 0, UUID_DCE);
++ }
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_OTHER);
++ return 0;
++}
+
+=== added file 'libvolume_id/lsi_raid.c'
+--- grub-0.97.orig/libvolume_id/lsi_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/lsi_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,55 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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;
++
++ info("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((char *)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;
++}
+
+=== added file 'libvolume_id/luks.c'
+--- grub-0.97.orig/libvolume_id/luks.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/luks.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,76 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 W. Michael Petullo <mike@flyn.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define LUKS_SECTOR_SHIFT 9
++#define LUKS_SECTOR_SIZE (1 << LUKS_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
++
++#define LUKS_MAGIC_L 6
++#define LUKS_PHDR_SIZE (sizeof(struct luks_phdr)/LUKS_SECTOR_SIZE+1)
++#define UUID_STRING_L 40
++static const uint8_t LUKS_MAGIC[] = {'L','U','K','S', 0xba, 0xbe};
++
++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, uint64_t size)
++{
++ struct luks_phdr *header;
++
++ header = (struct luks_phdr*) volume_id_get_buffer(id, off, LUKS_PHDR_SIZE);
++ if (header == NULL)
++ return -1;
++
++ if (memcmp((char *)header->magic, (char *)LUKS_MAGIC, LUKS_MAGIC_L))
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_CRYPTO);
++ volume_id_set_uuid(id, header->uuid, 36, UUID_HEX_STRING);
++ sprintf(id->type_version, "%u", le16_to_cpu(header->version));
++ id->type = "crypto_LUKS";
++ return 0;
++}
+
+=== added file 'libvolume_id/lvm.c'
+--- grub-0.97.orig/libvolume_id/lvm.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/lvm.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,92 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ const uint8_t *buf;
++ struct lvm1_super_block *lvm;
++
++ info("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((char *)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, uint64_t size)
++{
++ 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((char *)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;
++}
+
+=== added file 'libvolume_id/minix.c'
+--- grub-0.97.orig/libvolume_id/minix.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/minix.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,112 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define MINIX_SUPERBLOCK_OFFSET 0x400
++
++#define MINIX_SUPER_MAGIC 0x137F
++#define MINIX_SUPER_MAGIC2 0x138F
++#define MINIX2_SUPER_MAGIC 0x2468
++#define MINIX2_SUPER_MAGIC2 0x2478
++#define MINIX3_SUPER_MAGIC 0x4d5a
++
++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;
++
++struct minix3_super_block {
++ uint32_t s_ninodes;
++ uint16_t s_pad0;
++ uint16_t s_imap_blocks;
++ uint16_t s_zmap_blocks;
++ uint16_t s_firstdatazone;
++ uint16_t s_log_zone_size;
++ uint16_t s_pad1;
++ uint32_t s_max_size;
++ uint32_t s_zones;
++ uint16_t s_magic;
++ uint16_t s_pad2;
++ uint16_t s_blocksize;
++ uint8_t s_disk_version;
++} PACKED;
++
++int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint8_t *buf;
++ struct minix_super_block *ms;
++ struct minix3_super_block *m3s;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ ms = (struct minix_super_block *) buf;
++
++ if (ms->s_magic == MINIX_SUPER_MAGIC ||
++ ms->s_magic == bswap_16(MINIX_SUPER_MAGIC)) {
++ strcpy(id->type_version, "1");
++ goto found;
++ }
++ if (ms->s_magic == MINIX_SUPER_MAGIC2 ||
++ ms->s_magic == bswap_16(MINIX_SUPER_MAGIC2)) {
++ strcpy(id->type_version, "1");
++ goto found;
++ }
++ if (ms->s_magic == MINIX2_SUPER_MAGIC ||
++ ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC)) {
++ strcpy(id->type_version, "2");
++ goto found;
++ }
++ if (ms->s_magic == MINIX2_SUPER_MAGIC2 ||
++ ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC2)) {
++ strcpy(id->type_version, "2");
++ goto found;
++ }
++
++ m3s = (struct minix3_super_block *) buf;
++ if (m3s->s_magic == MINIX3_SUPER_MAGIC ||
++ m3s->s_magic == bswap_16(MINIX3_SUPER_MAGIC)) {
++ strcpy(id->type_version, "3");
++ goto found;
++ }
++ goto exit;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "minix";
++ return 0;
++
++exit:
++ return -1;
++}
+
+=== added file 'libvolume_id/misc.c'
+--- grub-0.97.orig/libvolume_id/misc.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/misc.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,34 @@
++/*
++ * volume_id/misc.c
++ *
++ * Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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.
++ */
++#define _GNU_SOURCE
++#include <string.h>
++
++/*
++ * Misc auxiliary functions required for volume_id inside grub
++ */
++size_t strnlen(const char *s, size_t limit)
++{
++ size_t length = 0;
++ while ( (length < limit) && (*s++) )
++ length++;
++
++ return length;
++}
++
++char *strchr (const char *s, int c)
++{
++ do {
++ if ( *s == c ) {
++ return (char*)s;
++ }
++ } while ( *s++ );
++
++ return 0;
++}
+
+=== added file 'libvolume_id/netware.c'
+--- grub-0.97.orig/libvolume_id/netware.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/netware.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,98 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define NW_SUPERBLOCK_OFFSET 0x1000
++
++struct netware_super_block {
++ uint8_t SBH_Signature[4];
++ uint16_t SBH_VersionMajor;
++ uint16_t SBH_VersionMinor;
++ uint16_t SBH_VersionMediaMajor;
++ uint16_t SBH_VersionMediaMinor;
++ uint32_t SBH_ItemsMoved;
++ uint8_t SBH_InternalID[16];
++ uint32_t SBH_PackedSize;
++ uint32_t SBH_Checksum;
++ uint32_t supersyncid;
++ int64_t superlocation[4];
++ uint32_t physSizeUsed;
++ uint32_t sizeUsed;
++ uint32_t superTimeStamp;
++ uint32_t reserved0[1];
++ int64_t SBH_LoggedPoolDataBlk;
++ int64_t SBH_PoolDataBlk;
++ uint8_t SBH_OldInternalID[16];
++ uint32_t SBH_PoolToLVStartUTC;
++ uint32_t SBH_PoolToLVEndUTC;
++ uint16_t SBH_VersionMediaMajorCreate;
++ uint16_t SBH_VersionMediaMinorCreate;
++ uint32_t SBH_BlocksMoved;
++ uint32_t SBH_TempBTSpBlk;
++ uint32_t SBH_TempFTSpBlk;
++ uint32_t SBH_TempFTSpBlk1;
++ uint32_t SBH_TempFTSpBlk2;
++ uint32_t nssMagicNumber;
++ uint32_t poolClassID;
++ uint32_t poolID;
++ uint32_t createTime;
++ int64_t SBH_LoggedVolumeDataBlk;
++ int64_t SBH_VolumeDataBlk;
++ int64_t SBH_SystemBeastBlkNum;
++ uint64_t totalblocks;
++ uint16_t SBH_Name[64];
++ uint8_t SBH_VolumeID[16];
++ uint8_t SBH_PoolID[16];
++ uint8_t SBH_PoolInternalID[16];
++ uint64_t SBH_Lsn;
++ uint32_t SBH_SS_Enabled;
++ uint32_t SBH_SS_CreateTime;
++ uint8_t SBH_SS_OriginalPoolID[16];
++ uint8_t SBH_SS_OriginalVolumeID[16];
++ uint8_t SBH_SS_Guid[16];
++ uint16_t SBH_SS_OriginalName[64];
++ uint32_t reserved2[64-(2+46)];
++} PACKED;
++
++int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct netware_super_block *nw;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ nw = (struct netware_super_block *) volume_id_get_buffer(id, off + NW_SUPERBLOCK_OFFSET, 0x200);
++ if (nw == NULL)
++ return -1;
++
++ if (memcmp((char *)nw->SBH_Signature, "SPB5", 4) != 0)
++ return -1;
++
++ volume_id_set_uuid(id, nw->SBH_PoolID, 0, UUID_DCE);
++
++ sprintf(id->type_version, "%u.%02u",
++ le16_to_cpu(nw->SBH_VersionMediaMajor), le16_to_cpu(nw->SBH_VersionMediaMinor));
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "nss";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/ntfs.c'
+--- grub-0.97.orig/libvolume_id/ntfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ntfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,192 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++static 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;
++
++static 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;
++
++static 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;
++
++static 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
++
++#undef debug
++#define debug grub_printf
++
++int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ 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;
++
++ info("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((char *)ns->oem_id, "NTFS", 4) != 0)
++ return -1;
++
++ volume_id_set_uuid(id, ns->volume_serial, 0, UUID_64BIT_LE);
++
++ sector_size = le16_to_cpu(ns->bytes_per_sector);
++ if (sector_size < 0x200)
++ return -1;
++
++ 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)
++ return -1;
++
++ 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((char *)mftr->magic, "FILE", 4) != 0)
++ return -1;
++
++ 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);
++ sprintf(id->type_version, "%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);
++ }
++ }
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "ntfs";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/nvidia_raid.c'
+--- grub-0.97.orig/libvolume_id/nvidia_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/nvidia_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,59 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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;
++
++ info("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((char *)nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u", le16_to_cpu(nv->version));
++ id->type = "nvidia_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/ocfs.c'
+--- grub-0.97.orig/libvolume_id/ocfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ocfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,186 @@
++/*
++ * 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>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ const uint8_t *buf;
++ struct ocfs1_super_block_header *osh;
++ struct ocfs1_super_block_label *osl;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ osh = (struct ocfs1_super_block_header *) buf;
++ if (memcmp((char *)osh->signature, "OracleCFS", 9) != 0)
++ return -1;
++ sprintf(id->type_version, "%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, 0, 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, uint64_t size)
++{
++ const uint8_t *buf;
++ struct ocfs2_super_block *os;
++ size_t blksize;
++
++ info("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((char *)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, 0, UUID_DCE);
++ sprintf(id->type_version, "%u.%u", os->s_major_rev_level, os->s_minor_rev_level);
++ id->type = "ocfs2";
++ return 0;
++ }
++ return -1;
++}
+
+=== added file 'libvolume_id/promise_raid.c'
+--- grub-0.97.orig/libvolume_id/promise_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/promise_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,65 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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
++ };
++
++ info("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((char *)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;
++}
+
+=== added file 'libvolume_id/reiserfs.c'
+--- grub-0.97.orig/libvolume_id/reiserfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/reiserfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,113 @@
++/*
++ * 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>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct reiserfs_super_block *rs;
++ struct reiser4_super_block *rs4;
++ uint8_t *buf;
++
++ info("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((char *)rs->magic, "ReIsErFs", 8) == 0) {
++ strcpy(id->type_version, "3.5");
++ id->type = "reiserfs";
++ goto found;
++ }
++ if (memcmp((char *)rs->magic, "ReIsEr2Fs", 9) == 0) {
++ strcpy(id->type_version, "3.6");
++ id->type = "reiserfs";
++ goto found_label;
++ }
++ if (memcmp((char *)rs->magic, "ReIsEr3Fs", 9) == 0) {
++ strcpy(id->type_version, "JR");
++ id->type = "reiserfs";
++ goto found_label;
++ }
++
++ rs4 = (struct reiser4_super_block *) buf;
++ if (memcmp((char *)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, 0, 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((char *)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, 0, UUID_DCE);
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++
++ return 0;
++}
+
+=== added file 'libvolume_id/romfs.c'
+--- grub-0.97.orig/libvolume_id/romfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/romfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,55 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct romfs_super *rfs;
++
++ info("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((char *)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;
++}
+
+=== added file 'libvolume_id/silicon_raid.c'
+--- grub-0.97.orig/libvolume_id/silicon_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/silicon_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,71 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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;
++
++ info("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);
++ sprintf(id->type_version, "%u.%u", le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver));
++ id->type = "silicon_medley_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/squashfs.c'
+--- grub-0.97.orig/libvolume_id/squashfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/squashfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,63 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define SQUASHFS_MAGIC 0x73717368
++
++struct squashfs_super {
++ uint32_t s_magic;
++ uint32_t inodes;
++ uint32_t bytes_used_2;
++ uint32_t uid_start_2;
++ uint32_t guid_start_2;
++ uint32_t inode_table_start_2;
++ uint32_t directory_table_start_2;
++ uint16_t s_major;
++ uint16_t s_minor;
++} PACKED;
++
++int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct squashfs_super *sqs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ sqs = (struct squashfs_super *) volume_id_get_buffer(id, off, 0x200);
++ if (sqs == NULL)
++ return -1;
++
++ if (sqs->s_magic == SQUASHFS_MAGIC) {
++ sprintf(id->type_version, "%u.%u", sqs->s_major, sqs->s_minor);
++ goto found;
++ }
++ if (sqs->s_magic == bswap_32(SQUASHFS_MAGIC)) {
++ sprintf(id->type_version, "%u.%u", bswap_16(sqs->s_major), bswap_16(sqs->s_minor));
++ goto found;
++ }
++
++ return -1;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "squashfs";
++ return 0;
++}
+
+=== added file 'libvolume_id/strfuncs.h'
+--- grub-0.97.orig/libvolume_id/strfuncs.h 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/strfuncs.h 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,5 @@
++
++#include <stdlib.h>
++
++size_t strnlen(const char *s, size_t limit);
++char *strchr (const char *s, int c);
+
+=== added file 'libvolume_id/sysv.c'
+--- grub-0.97.orig/libvolume_id/sysv.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/sysv.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,128 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct sysv_super *vs;
++ struct xenix_super *xs;
++ unsigned int boff;
++
++ info("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;
++}
+
+=== added file 'libvolume_id/udf.c'
+--- grub-0.97.orig/libvolume_id/udf.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/udf.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,173 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ 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;
++
++ info("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((char *)vsd->id, "NSR02", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "NSR03", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "BEA01", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "BOOT2", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "CD001", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "CDW02", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)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((char *)vsd->id, "NSR02", 5) == 0)
++ goto anchor;
++ if (memcmp((char *)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;
++}
+
+=== added file 'libvolume_id/ufs.c'
+--- grub-0.97.orig/libvolume_id/ufs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ufs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,217 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ uint32_t magic;
++ int i;
++ struct ufs_super_block *ufs;
++ int offsets[] = {0, 8, 64, 256, -1};
++
++ info("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";
++ switch (magic) {
++ case UFS_MAGIC:
++ strcpy(id->type_version, "1");
++ break;
++ case UFS2_MAGIC:
++ strcpy(id->type_version, "2");
++ volume_id_set_label_raw(id, ufs->fs_u11.fs_u2.fs_volname, 32);
++ volume_id_set_label_string(id, ufs->fs_u11.fs_u2.fs_volname, 32);
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
+
+=== added file 'libvolume_id/util.c'
+--- grub-0.97.orig/libvolume_id/util.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/util.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,472 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 <stdlib.h>
++
++#include "strfuncs.h"
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++static char hex[] = "0123456789abcdef";
++
++#define hexhi(val) hex[val >> 4]
++#define hexlo(val) hex[val & 0xf]
++
++/* count of characters used to encode one unicode char */
++static int utf8_encoded_expected_len(const char *str)
++{
++ unsigned char c = (unsigned char)str[0];
++
++ if (c < 0x80)
++ return 1;
++ if ((c & 0xe0) == 0xc0)
++ return 2;
++ if ((c & 0xf0) == 0xe0)
++ return 3;
++ if ((c & 0xf8) == 0xf0)
++ return 4;
++ if ((c & 0xfc) == 0xf8)
++ return 5;
++ if ((c & 0xfe) == 0xfc)
++ return 6;
++ return 0;
++}
++
++/* decode one unicode char */
++static int utf8_encoded_to_unichar(const char *str)
++{
++ int unichar;
++ int len;
++ int i;
++
++ len = utf8_encoded_expected_len(str);
++ switch (len) {
++ case 1:
++ return (int)str[0];
++ case 2:
++ unichar = str[0] & 0x1f;
++ break;
++ case 3:
++ unichar = (int)str[0] & 0x0f;
++ break;
++ case 4:
++ unichar = (int)str[0] & 0x07;
++ break;
++ case 5:
++ unichar = (int)str[0] & 0x03;
++ break;
++ case 6:
++ unichar = (int)str[0] & 0x01;
++ break;
++ default:
++ return -1;
++ }
++
++ for (i = 1; i < len; i++) {
++ if (((int)str[i] & 0xc0) != 0x80)
++ return -1;
++ unichar <<= 6;
++ unichar |= (int)str[i] & 0x3f;
++ }
++
++ return unichar;
++}
++
++/* expected size used to encode one unicode char */
++static int utf8_unichar_to_encoded_len(int unichar)
++{
++ if (unichar < 0x80)
++ return 1;
++ if (unichar < 0x800)
++ return 2;
++ if (unichar < 0x10000)
++ return 3;
++ if (unichar < 0x200000)
++ return 4;
++ if (unichar < 0x4000000)
++ return 5;
++ return 6;
++}
++
++/* check if unicode char has a valid numeric range */
++static int utf8_unichar_valid_range(int unichar)
++{
++ if (unichar > 0x10ffff)
++ return 0;
++ if ((unichar & 0xfffff800) == 0xd800)
++ return 0;
++ if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
++ return 0;
++ if ((unichar & 0xffff) == 0xffff)
++ return 0;
++ return 1;
++}
++
++/* validate one encoded unicode char and return its length */
++int volume_id_utf8_encoded_valid_unichar(const char *str)
++{
++ int len;
++ int unichar;
++ int i;
++
++ len = utf8_encoded_expected_len(str);
++ if (len == 0)
++ return -1;
++
++ /* ascii is valid */
++ if (len == 1)
++ return 1;
++
++ /* check if expected encoded chars are available */
++ for (i = 0; i < len; i++)
++ if ((str[i] & 0x80) != 0x80)
++ return -1;
++
++ unichar = utf8_encoded_to_unichar(str);
++
++ /* check if encoded length matches encoded value */
++ if (utf8_unichar_to_encoded_len(unichar) != len)
++ return -1;
++
++ /* check if value has valid range */
++ if (!utf8_unichar_valid_range(unichar))
++ return -1;
++
++ return len;
++}
++
++size_t volume_id_set_unicode16(uint8_t *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count)
++{
++ size_t 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';
++ return j;
++}
++
++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)
++{
++ if (count > sizeof(id->label))
++ count = sizeof(id->label);
++
++ 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)
++{
++ size_t i;
++
++ if (count >= sizeof(id->label))
++ count = sizeof(id->label)-1;
++
++ memcpy(id->label, buf, count);
++ id->label[count] = '\0';
++
++ /* 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)
++{
++ if (count >= sizeof(id->label))
++ count = sizeof(id->label)-1;
++
++ volume_id_set_unicode16((uint8_t *)id->label, sizeof(id->label), buf, endianess, count);
++}
++
++void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, size_t len, enum uuid_format format)
++{
++ unsigned int i;
++ unsigned int count = 0;
++ char *uuid;
++
++ if (len > sizeof(id->uuid_raw))
++ len = sizeof(id->uuid_raw);
++
++ switch(format) {
++ case UUID_STRING:
++ count = len;
++ break;
++ case UUID_HEX_STRING:
++ count = len;
++ break;
++ case UUID_DOS:
++ count = 4;
++ break;
++ case UUID_64BIT_LE:
++ case UUID_64BIT_BE:
++ count = 8;
++ break;
++ case UUID_DCE:
++ count = 16;
++ break;
++ case UUID_FOURINT:
++ count = 35;
++ 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:
++ uuid = id->uuid;
++ switch(format) {
++ case UUID_DOS:
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid = '\0';
++ break;
++ case UUID_64BIT_LE:
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid = '\0';
++ break;
++ case UUID_64BIT_BE:
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid = '\0';
++ break;
++ case UUID_DCE:
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[8]);
++ *uuid++ = hexlo(buf[8]);
++ *uuid++ = hexhi(buf[9]);
++ *uuid++ = hexlo(buf[9]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[10]);
++ *uuid++ = hexlo(buf[10]);
++ *uuid++ = hexhi(buf[11]);
++ *uuid++ = hexlo(buf[11]);
++ *uuid++ = hexhi(buf[12]);
++ *uuid++ = hexlo(buf[12]);
++ *uuid++ = hexhi(buf[13]);
++ *uuid++ = hexlo(buf[13]);
++ *uuid++ = hexhi(buf[14]);
++ *uuid++ = hexlo(buf[14]);
++ *uuid++ = hexhi(buf[15]);
++ *uuid++ = hexlo(buf[15]);
++ *uuid = '\0';
++ break;
++ case UUID_HEX_STRING:
++ /* translate A..F to a..f */
++ memcpy(id->uuid, buf, count);
++ for (i = 0; i < count; i++)
++ if (id->uuid[i] >= 'A' && id->uuid[i] <= 'F')
++ id->uuid[i] = (id->uuid[i] - 'A') + 'a';
++ id->uuid[count] = '\0';
++ break;
++ case UUID_STRING:
++ memcpy(id->uuid, buf, count);
++ id->uuid[count] = '\0';
++ break;
++ case UUID_FOURINT:
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = ':';
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid++ = ':';
++ *uuid++ = hexhi(buf[8]);
++ *uuid++ = hexlo(buf[8]);
++ *uuid++ = hexhi(buf[9]);
++ *uuid++ = hexlo(buf[9]);
++ *uuid++ = hexhi(buf[10]);
++ *uuid++ = hexlo(buf[10]);
++ *uuid++ = hexhi(buf[11]);
++ *uuid++ = hexlo(buf[11]);
++ *uuid++ = ':';
++ *uuid++ = hexhi(buf[12]);
++ *uuid++ = hexlo(buf[12]);
++ *uuid++ = hexhi(buf[13]);
++ *uuid++ = hexlo(buf[13]);
++ *uuid++ = hexhi(buf[14]);
++ *uuid++ = hexlo(buf[14]);
++ *uuid++ = hexhi(buf[15]);
++ *uuid++ = hexlo(buf[15]);
++ *uuid = '\0';
++ break;
++ default:
++ *uuid = '\0';
++ break;
++ }
++}
++
++uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
++{
++ info("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) {
++ /* check if we need to read */
++ if ((off + len) > id->sbbuf_len) {
++ if (devread (0, 0, off + len, (char*)id->sbbuf) == 0)
++ {
++ return NULL;
++ }
++ id->sbbuf_len = off + len;
++ }
++ return &(id->sbbuf[off]);
++ } else {
++ if (len > SEEK_BUFFER_SIZE) {
++ dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
++ return NULL;
++ }
++
++ /* check if we need to read */
++ if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
++ info("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len);
++ if (devread(off >> 9, off & 0x1ff, len, (char*)id->seekbuf) == 0)
++ {
++ return NULL;
++ }
++ id->seekbuf_off = off;
++ id->seekbuf_len = len;
++ }
++ return &(id->seekbuf[off - id->seekbuf_off]);
++ }
++}
+
+=== added file 'libvolume_id/util.h'
+--- grub-0.97.orig/libvolume_id/util.h 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/util.h 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,98 @@
++/*
++ * 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 ALLOWED_CHARS "#+-.:=@_"
++
++#ifndef PACKED
++#define PACKED __attribute__((packed))
++#endif
++
++#define err(format, arg...) volume_id_log_fn(LOG_ERR, __FILE__, __LINE__, format, ##arg)
++#ifdef INFO
++#define info(format, arg...) volume_id_log_fn(LOG_INFO, __FILE__, __LINE__, format, ##arg)
++#else
++#define info(format, arg...) do { } while (0)
++#endif
++
++#ifdef DEBUG
++#define dbg(format, arg...) volume_id_log_fn(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_STRING,
++ UUID_HEX_STRING,
++ UUID_DCE,
++ UUID_DOS,
++ UUID_64BIT_LE,
++ UUID_64BIT_BE,
++ UUID_FOURINT,
++};
++
++enum endian {
++ LE = 0,
++ BE = 1
++};
++
++extern int volume_id_utf8_encoded_valid_unichar(const char *str);
++extern size_t volume_id_set_unicode16(uint8_t *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, size_t len, 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_ */
++
+
+=== added file 'libvolume_id/via_raid.c'
+--- grub-0.97.orig/libvolume_id/via_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/via_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,88 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * Based on information taken from dmraid:
++ * Copyright (C) 2004-2006 Heinz Mauelshagen, Red Hat GmbH
++ *
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct via_meta {
++ uint16_t signature;
++ uint8_t version_number;
++ struct via_array {
++ uint16_t disk_bit_mask;
++ uint8_t disk_array_ex;
++ uint32_t capacity_low;
++ uint32_t capacity_high;
++ uint32_t serial_checksum;
++ } PACKED array;
++ uint32_t serial_checksum[8];
++ uint8_t checksum;
++} PACKED;
++
++#define VIA_SIGNATURE 0xAA55
++
++/* 8 bit checksum on first 50 bytes of metadata. */
++static uint8_t meta_checksum(struct via_meta *via)
++{
++ uint8_t i = 50, sum = 0;
++
++ while (i--)
++ sum += ((uint8_t*) via)[i];
++
++ return sum == via->checksum;
++}
++
++
++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;
++
++ if (!meta_checksum(via))
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u", via->version_number);
++ id->type = "via_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/volume_id.c'
+--- grub-0.97.orig/libvolume_id/volume_id.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/volume_id.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,222 @@
++/*
++ * volume_id - reads volume label and uuid
++ *
++ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * 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 <fcntl.h>
++#include <sys/stat.h>
++
++#include "volume_id.h"
++#include "util.h"
++#include "strfuncs.h"
++#include "shared.h"
++
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++struct prober {
++ volume_id_probe_fn_t prober;
++ const char *name[4];
++};
++
++#define NOT_SUPPORTED(x)
++#define SUPPORTED(x) x
++
++static const struct prober prober_raid[] = {
++ { volume_id_probe_ddf_raid, { "ddf_raid", } },
++
++ /* { volume_id_probe_linux_raid, { "linux_raid", } }, */
++ /* { volume_id_probe_intel_software_raid, { "isw_raid", } }, */
++ /* { volume_id_probe_lsi_mega_raid, { "lsi_mega_raid", } }, */
++ /* { volume_id_probe_via_raid, { "via_raid", } }, */
++ /* { volume_id_probe_silicon_medley_raid, { "silicon_medley_raid", } }, */
++ /* { volume_id_probe_nvidia_raid, { "nvidia_raid", } }, */
++ /* { volume_id_probe_promise_fasttrack_raid, { "promise_fasttrack_raid", } }, */
++ /* { volume_id_probe_highpoint_45x_raid, { "highpoint_raid", } }, */
++ /* { volume_id_probe_adaptec_raid, { "adaptec_raid", } }, */
++ /* { volume_id_probe_jmicron_raid, { "jmicron_raid", } }, */
++ /* { volume_id_probe_lvm1, { "lvm1", } }, */
++ /* { volume_id_probe_lvm2, { "lvm2", } }, */
++ /* { volume_id_probe_highpoint_37x_raid, { "highpoint_raid", } }, */
++};
++
++static const struct prober prober_filesystem[] = {
++ { volume_id_probe_vfat, { "vfat", } },
++ { volume_id_probe_luks, { "luks", } },
++ { volume_id_probe_xfs, { "xfs", } },
++ { volume_id_probe_ext, { "ext2", "ext3", "jbd", } },
++ { volume_id_probe_reiserfs, { "reiserfs", "reiser4", } },
++ { volume_id_probe_jfs, { "jfs", } },
++ { volume_id_probe_hfs_hfsplus, { "hfs", "hfsplus", } },
++ { volume_id_probe_ntfs, { "ntfs", } },
++ { volume_id_probe_ocfs1, { "ocfs1", } },
++ { volume_id_probe_ocfs2, { "ocfs2", } },
++
++ /* { volume_id_probe_linux_swap, { "swap", } }, */
++ /* { volume_id_probe_udf, { "udf", } }, */
++ /* { volume_id_probe_iso9660, { "iso9660", } }, */
++ /* { volume_id_probe_ufs, { "ufs", } }, */
++ /* { volume_id_probe_cramfs, { "cramfs", } }, */
++ /* { volume_id_probe_romfs, { "romfs", } }, */
++ /* { volume_id_probe_hpfs, { "hpfs", } }, */
++ /* { volume_id_probe_sysv, { "sysv", "xenix", } }, */
++ /* { volume_id_probe_minix, { "minix", } }, */
++ /* { volume_id_probe_vxfs, { "vxfs", } }, */
++ /* { volume_id_probe_squashfs, { "squashfs", } }, */
++ /* { volume_id_probe_netware, { "netware", } }, */
++};
++
++/* 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_t volume_id_log_fn = default_log;
++
++/**
++ * volume_id_get_type:
++ * @id: Probing context
++ * @type: Type string. Must not be freed by the caller.
++ *
++ * Get the type string after a successful probe.
++ *
++ * Returns: 1 if the value was set, 0 otherwise.
++ **/
++int volume_id_get_type(struct volume_id *id, const char **type)
++{
++ if (id == NULL)
++ return 0;
++ if (type == NULL)
++ return 0;
++ if (id->usage_id == VOLUME_ID_UNUSED)
++ return 0;
++
++ *type = id->type;
++ return 1;
++}
++
++
++/**
++ * volume_id_get_uuid:
++ * @id: Probing context.
++ * @uuid: UUID string. Must not be freed by the caller.
++ *
++ * Get the raw UUID string after a successful probe.
++ *
++ * Returns: 1 if the value was set, 0 otherwise.
++ **/
++int volume_id_get_uuid(struct volume_id *id, const char **uuid)
++{
++ if (id == NULL)
++ return 0;
++ if (uuid == NULL)
++ return 0;
++ if (id->usage_id == VOLUME_ID_UNUSED)
++ return 0;
++
++ *uuid = id->uuid;
++ return 1;
++}
++
++/**
++ * volume_id_probe_raid:
++ * @id: Probing context.
++ * @off: Probing offset relative to the start of the device.
++ * @size: Total size of the device.
++ *
++ * Probe device for all known raid signatures.
++ *
++ * Returns: 0 on successful probe, otherwise negative value.
++ **/
++int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ unsigned int i;
++
++ if (id == NULL)
++ return -1;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ for (i = 0; i < ARRAY_SIZE(prober_raid); i++)
++ if (prober_raid[i].prober(id, off, size) == 0)
++ goto found;
++ return -1;
++
++found:
++ return 0;
++}
++
++/**
++ * volume_id_probe_filesystem:
++ * @id: Probing context.
++ * @off: Probing offset relative to the start of the device.
++ * @size: Total size of the device.
++ *
++ * Probe device for all known filesystem signatures.
++ *
++ * Returns: 0 on successful probe, otherwise negative value.
++ **/
++int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ unsigned int i;
++
++ if (id == NULL)
++ return -1;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++)
++ if (prober_filesystem[i].prober(id, off, size) == 0)
++ goto found;
++ return -1;
++
++found:
++ return 0;
++}
++
++/**
++ * volume_id_probe_raid:
++ * @all_probers_fn: prober function to called for all known probing routines.
++ * @id: Context passed to prober function.
++ * @off: Offset value passed to prober function.
++ * @size: Size value passed to prober function.
++ * @data: Arbitrary data passed to the prober function.
++ *
++ * Run a custom function for all known probing routines.
++ **/
++void volume_id_all_probers(all_probers_fn_t all_probers_fn,
++ struct volume_id *id, uint64_t off, uint64_t size,
++ void *data)
++{
++ unsigned int i;
++
++ if (all_probers_fn == NULL)
++ return;
++
++ for (i = 0; i < ARRAY_SIZE(prober_raid); i++) {
++ if (all_probers_fn(prober_raid[i].prober, id, off, size, data) != 0)
++ goto out;
++ }
++ for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++) {
++ if (all_probers_fn(prober_filesystem[i].prober, id, off, size, data) != 0)
++ goto out;
++ }
++out:
++ return;
++}
+
+=== added file 'libvolume_id/volume_id.h'
+--- grub-0.97.orig/libvolume_id/volume_id.h 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/volume_id.h 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,137 @@
++/*
++ * volume_id - reads volume label and uuid
++ *
++ * Copyright (C) 2005-2007 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>
++
++typedef void (*volume_id_log_fn_t)(int priority, const char *file, int line, const char *format, ...) ;
++
++extern volume_id_log_fn_t volume_id_log_fn;
++
++struct volume_id;
++typedef int (*volume_id_probe_fn_t)(struct volume_id *id, uint64_t off, uint64_t size);
++typedef int (*all_probers_fn_t)(volume_id_probe_fn_t probe_fn,
++ struct volume_id *id, uint64_t off, uint64_t size,
++ void *data);
++
++extern struct volume_id *volume_id_open_fd(int fd);
++extern void volume_id_close(struct volume_id *id);
++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 int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size);
++extern const volume_id_probe_fn_t *volume_id_get_prober_by_type(const char *type);
++extern void volume_id_all_probers(all_probers_fn_t all_probers_fn,
++ struct volume_id *id, uint64_t off, uint64_t size,
++ void *data);
++extern int volume_id_get_label(struct volume_id *id, const char **label);
++extern int volume_id_get_label_raw(struct volume_id *id, const uint8_t **label, size_t *len);
++extern int volume_id_get_uuid(struct volume_id *id, const char **uuid);
++extern int volume_id_get_uuid_raw(struct volume_id *id, const uint8_t **uuid, size_t *len);
++extern int volume_id_get_usage(struct volume_id *id, const char **usage);
++extern int volume_id_get_type(struct volume_id *id, const char **type);
++extern int volume_id_get_type_version(struct volume_id *id, const char **type_version);
++extern int volume_id_encode_string(const char *str, char *str_enc, size_t len);
++
++/*
++ * Note: everything below will be made private or removed from
++ * a future version, and a new major release of libvolume_id
++ */
++
++extern struct volume_id *volume_id_open_node(const char *path);
++
++#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,
++};
++
++#include <util.h>
++
++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[SB_BUFFER_SIZE];
++ size_t sbbuf_len;
++ uint8_t seekbuf[SEEK_BUFFER_SIZE];
++ uint64_t seekbuf_off;
++ size_t seekbuf_len;
++ int fd_close:1;
++};
++
++/* filesystems */
++extern int volume_id_probe_cramfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_romfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_sysv(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_vxfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_xfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size);
++
++/* special formats */
++extern int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size);
++
++/* 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, uint64_t size);
++extern int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size);
++
++/* 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, uint64_t size);
++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);
++extern int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size);
++
++#endif
+
+=== added file 'libvolume_id/vxfs.c'
+--- grub-0.97.orig/libvolume_id/vxfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/vxfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,49 @@
++/*
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct vxfs_super *vxs;
++
++ info("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)) {
++ sprintf(id->type_version, "%u", (unsigned int) vxs->vs_version);
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "vxfs";
++ return 0;
++ }
++
++ return -1;
++}
+
+=== added file 'libvolume_id/xfs.c'
+--- grub-0.97.orig/libvolume_id/xfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/xfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,59 @@
++/*
++ * 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 "volume_id.h"
++#include "util.h"
++#include "shared.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, uint64_t size)
++{
++ struct xfs_super_block *xs;
++
++ info("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((char *)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, 0, UUID_DCE);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "xfs";
++
++ return 0;
++}
+
+=== modified file 'stage2/Makefile.am'
+--- grub-0.97.orig/stage2/Makefile.am 2005-02-02 20:40:05 +0000
++++ grub-0.97/stage2/Makefile.am 2008-07-09 17:23:44 +0000
+@@ -13,6 +13,10 @@
+ # For <stage1.h>.
+ INCLUDES = -I$(top_srcdir)/stage1
+
++if UUID_SUPPORT
++INCLUDES += -I$(top_srcdir)/libvolume_id
++endif
++
+ # The library for /sbin/grub.
+ noinst_LIBRARIES = libgrub.a
+ libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
+@@ -61,6 +65,12 @@
+ PXELOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
+ START_ELTORITO_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
+
++if UUID_SUPPORT
++UUID_FLAGS = -DSUPPORT_UUID=1
++else
++UUID_FLAGS =
++endif
++
+ if NETBOOT_SUPPORT
+ NETBOOT_FLAGS = -I$(top_srcdir)/netboot -DSUPPORT_NETBOOT=1
+ else
+@@ -82,6 +92,8 @@
+ STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
+ $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS)
+
++STAGE2_COMPILE += $(UUID_FLAGS)
++
+ STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
+ STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1
+
+@@ -97,7 +109,12 @@
+
+ if NETBOOT_SUPPORT
+ pre_stage2_exec_LDADD = ../netboot/libdrivers.a
+-endif
++else
++if UUID_SUPPORT
++pre_stage2_exec_LDADD = ../libvolume_id/libvolume_id.a
++endif
++endif
++
+
+ if DISKLESS_SUPPORT
+ BUILT_SOURCES = stage2_size.h diskless_size.h
+
+=== modified file 'stage2/builtins.c'
+--- grub-0.97.orig/stage2/builtins.c 2008-01-28 18:15:31 +0000
++++ grub-0.97/stage2/builtins.c 2008-07-09 17:23:44 +0000
+@@ -49,6 +49,10 @@
+ # include <md5.h>
+ #endif
+
++#ifdef SUPPORT_UUID
++#include <volume_id.h>
++#endif
++
+ /* The type of kernel loaded. */
+ kernel_t kernel_type;
+ /* The boot device. */
+@@ -4790,6 +4794,168 @@
+ "Probe VBE information. If the mode number MODE is specified, show only"
+ " the information about only the mode."
+ };
++
++
++
++#ifdef SUPPORT_UUID
++
++struct uuid_callback_data
++{
++ int found; /* 1 if uuid matches */
++ char *uuid; /* uuid to look for */
++};
++
++static void uuid_info_print(struct volume_id *id, const char *uuid)
++{
++ const char *type;
++ int i;
++
++ volume_id_get_type(id, &type);
++ grub_printf("(hd%d", current_drive - 0x80);
++ if ((current_partition & 0xFF0000) != 0xFF0000)
++ {
++ grub_printf (",%d", (current_partition >> 16) & 0xFF);
++ }
++ if ((current_partition & 0x00FF00) != 0x00FF00)
++ {
++ grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
++ }
++ grub_printf(") %s",type);
++ for (i=0;i<6-strlen(type);i++)
++ {
++ grub_putchar(' ');
++ }
++ grub_printf(" %s\n",uuid);
++}
++
++static int uuid_all_probers(volume_id_probe_fn_t probe_fn,
++ struct volume_id *id,
++ uint64_t off,
++ uint64_t size,
++ void *data)
++{
++ struct uuid_callback_data *uc_data = (struct uuid_callback_data*)data;
++
++ if (probe_fn(id, off, size) == 0)
++ {
++ const char *volume_uuid;
++ if (volume_id_get_uuid(id, &volume_uuid))
++ {
++ if (!*(uc_data->uuid))
++ {
++ uuid_info_print(id, volume_uuid);
++ }
++ else
++ {
++ if (strcmp(volume_uuid, uc_data->uuid) == 0)
++ {
++ grub_printf("Boot from ");
++ uuid_info_print(id, volume_uuid);
++ uc_data->found = 1;
++ return 1;
++ }
++ }
++ }
++ }
++ return 0;
++}
++
++/* uuid find */
++/* Search for the uuid arg in all of partitions. */
++static int
++uuid_func(char *arg, int flag)
++{
++ unsigned long drive;
++ unsigned long tmp_drive = saved_drive;
++ unsigned long tmp_partition = saved_partition;
++ struct uuid_callback_data uc_data;
++
++ uc_data.uuid = arg;
++ uc_data.found = 0;
++
++ /* Just hard disks and USB drives supported by BIOS */
++ for (drive = 0x80; drive < 0x88; drive++)
++ {
++ unsigned long part = 0xFFFFFF;
++ unsigned long start, len, offset, ext_offset, gpt_offset;
++ int type, entry, gpt_count, gpt_size;
++ char *buf = (char *) RAW_ADDR(0x100000);
++ struct volume_id *vol_id = (struct volume_id *) RAW_ADDR (0x100000 + SECTOR_SIZE);
++
++ current_drive = drive;
++ while (next_partition (drive, 0xFFFFFF, &part, &type,
++ &start, &len, &offset, &entry,
++ &ext_offset, &gpt_offset,
++ &gpt_count, &gpt_size, buf))
++ {
++ if (type != PC_SLICE_TYPE_NONE
++ && ! IS_PC_SLICE_TYPE_BSD (type)
++ && ! IS_PC_SLICE_TYPE_EXTENDED (type))
++ {
++ current_partition = part;
++ errnum = ERR_NONE;
++ /* Attempt to open device, conventional way */
++ if (! open_device ())
++ {
++ errnum = ERR_NONE;
++ /* Failed, like NTFS or FAT filesystems, so try the rootnoverify way */
++ if (open_partition ())
++ {
++ set_bootdev (0);
++ if (errnum)
++ {
++ /* Give up */
++ errnum = ERR_NONE;
++ continue;
++ }
++ }
++ }
++
++ /* And probe for uuid across all fs types */
++ saved_drive = current_drive;
++ saved_partition = current_partition;
++
++ grub_memset(vol_id, 0, sizeof(struct volume_id) );
++ volume_id_all_probers(uuid_all_probers, vol_id, 0, len, (void*)&uc_data);
++ if (uc_data.found)
++ {
++ /* Success! */
++ errnum = ERR_NONE;
++ return 0;
++ }
++ }
++ /* We want to ignore any error here. */
++ errnum = ERR_NONE;
++ }
++
++ /* next_partition always sets ERRNUM in the last call, so clear it. */
++ errnum = ERR_NONE;
++ }
++
++ saved_drive = tmp_drive;
++ saved_partition = tmp_partition;
++ current_drive = GRUB_INVALID_DRIVE;
++ current_partition = 0xFFFFFF;
++ errnum = ERR_FILE_NOT_FOUND;
++
++ if (!*arg)
++ {
++ errnum = ERR_NONE;
++ return 0;
++ }
++ return 1;
++}
++
++static struct builtin builtin_uuid =
++{
++ "uuid",
++ uuid_func,
++ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++ "uuid UUID",
++ "Set the current \"root device\" to the device with the uuid UUID,"
++ " then attempt to mount it"
++};
++#endif
+
+
+ /* The table of builtin commands. Sorted in dictionary order. */
+@@ -4879,6 +5045,9 @@
+ &builtin_title,
+ &builtin_unhide,
+ &builtin_uppermem,
++#ifdef SUPPORT_UUID
++ &builtin_uuid,
++#endif
+ &builtin_vbeprobe,
+ 0
+ };
+