[syslinux] [RFC/PATCH] split chain into chain+iterator, expand iterators' code

Michal Soltys soltys at ziu.info
Sat Aug 7 17:10:05 PDT 2010


Patch:

- splits chain into chain and iterator parts and moves them into their
  own com32/chain directory
- extensively updates iterators' code
- adjusts chain.c to use new iterators
- fixes mbr/sect/hand/file allocation

Signed-off-by: Michal Soltys <soltys at ziu.info>
---
 Makefile                         |    2 +-
 com32/Makefile                   |    2 +-
 com32/chain/Makefile             |   39 ++
 com32/{modules => chain}/chain.c |  568 +++++++-----------------------
 com32/chain/partiter.c           |  714 ++++++++++++++++++++++++++++++++++++++
 com32/chain/partiter.h           |   94 +++++
 com32/modules/Makefile           |    2 +-
 7 files changed, 985 insertions(+), 436 deletions(-)
 create mode 100644 com32/chain/Makefile
 rename com32/{modules => chain}/chain.c (68%)
 create mode 100644 com32/chain/partiter.c
 create mode 100644 com32/chain/partiter.h

diff --git a/Makefile b/Makefile
index da90cdc..9ab401b 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@ include $(topdir)/MCONFIG
 MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \
 	com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
 	com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
-	com32/sysdump/*.c32 com32/lua/src/*.c32
+	com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32
 
 # syslinux.exe is BTARGET so as to not require everyone to have the
 # mingw suite installed
diff --git a/com32/Makefile b/com32/Makefile
index b090c40..43847bd 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,5 +1,5 @@
 SUBDIRS = tools lib gpllib libutil modules mboot menu samples rosh cmenu \
-	  hdt gfxboot sysdump lua/src
+	  hdt gfxboot sysdump lua/src chain
 
 all tidy dist clean spotless install:
 	set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/chain/Makefile b/com32/chain/Makefile
new file mode 100644
index 0000000..16086ba
--- /dev/null
+++ b/com32/chain/Makefile
@@ -0,0 +1,39 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 2001-2010 H. Peter Anvin - All Rights Reserved
+##   Copyright 2010 Michal Soltys
+##
+##   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, Inc., 53 Temple Place Ste 330,
+##   Boston MA 02111-1307, USA; either version 2 of the License, or
+##   (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+
+topdir = ../..
+include ../MCONFIG
+
+OBJS = chain.o partiter.o
+#GCCWARN += -Wextra -Wconversion -pedantic -Wno-error
+
+all: chain.c32
+
+chain.elf: $(OBJS) $(LIBS) $(C_LIBS)
+	$(LD) $(LDFLAGS) -o $@ $^
+
+tidy dist:
+	rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+	rm -f *.lnx
+
+spotless: clean
+	rm -f *.lss *.c32 *.com
+	rm -f *~ \#*
+
+install:
+
+
+-include .*.d
diff --git a/com32/modules/chain.c b/com32/chain/chain.c
similarity index 68%
rename from com32/modules/chain.c
rename to com32/chain/chain.c
index 60e3abc..68c2476 100644
--- a/com32/modules/chain.c
+++ b/com32/chain/chain.c
@@ -119,6 +119,7 @@
 #include <syslinux/config.h>
 #include <syslinux/disk.h>
 #include <syslinux/video.h>
+#include "partiter.h"
 
 static struct options {
     const char *loadfile;
@@ -148,319 +149,28 @@ static inline void error(const char *msg)
 static struct disk_info diskinfo;
 
 /* Search for a specific drive, based on the MBR signature; bytes 440-443 */
-static int find_disk(uint32_t mbr_sig)
+static int find_by_sig(uint32_t mbr_sig)
 {
+    struct part_iter *boot_part = NULL;
     int drive;
-    bool is_me;
-    struct disk_dos_mbr *mbr;
 
     for (drive = 0x80; drive <= 0xff; drive++) {
 	if (disk_get_params(drive, &diskinfo))
 	    continue;		/* Drive doesn't exist */
-	if (!(mbr = disk_read_sectors(&diskinfo, 0, 1)))
-	    continue;		/* Cannot read sector */
-	is_me = (mbr->disk_sig == mbr_sig);
-	free(mbr);
-	if (is_me)
-	    return drive;
-    }
-    return -1;
-}
-
-/* Forward declaration */
-struct disk_part_iter;
-
-/* Partition-/scheme-specific routine returning the next partition */
-typedef struct disk_part_iter *(*disk_part_iter_func) (struct disk_part_iter *
-						       part);
-
-/* Contains details for a partition under examination */
-struct disk_part_iter {
-    /* The block holding the table we are part of */
-    char *block;
-    /* The LBA for the beginning of data */
-    uint64_t lba_data;
-    /* The partition number, as determined by our heuristic */
-    int index;
-    /* The DOS partition record to pass, if applicable */
-    const struct disk_dos_part_entry *record;
-    /* Function returning the next available partition */
-    disk_part_iter_func next;
-    /* Partition-/scheme-specific details */
-    union {
-	/* MBR specifics */
-	int mbr_index;
-	/* EBR specifics */
-	struct {
-	    /* The first extended partition's start LBA */
-	    uint64_t lba_extended;
-	    /* Any applicable parent, or NULL */
-	    struct disk_part_iter *parent;
-	    /* The parent extended partition index */
-	    int parent_index;
-	} ebr;
-	/* GPT specifics */
-	struct {
-	    /* Real (not effective) index in the partition table */
-	    int index;
-	    /* Current partition GUID */
-	    const struct guid *part_guid;
-	    /* Current partition label */
-	    const char *part_label;
-	    /* Count of entries in GPT */
-	    int parts;
-	    /* Partition record size */
-	    uint32_t size;
-	} gpt;
-    } private;
-};
-
-static struct disk_part_iter *next_ebr_part(struct disk_part_iter *part)
-{
-    const struct disk_dos_part_entry *ebr_table;
-    const struct disk_dos_part_entry *parent_table =
-	((const struct disk_dos_mbr *)part->private.ebr.parent->block)->table;
-    static const struct disk_dos_part_entry phony = {.start_lba = 0 };
-    uint64_t ebr_lba;
-
-    /* Don't look for a "next EBR" the first time around */
-    if (part->private.ebr.parent_index >= 0)
-	/* Look at the linked list */
-	ebr_table = ((const struct disk_dos_mbr *)part->block)->table + 1;
-    /* Do we need to look for an extended partition? */
-    if (part->private.ebr.parent_index < 0 || !ebr_table->start_lba) {
-	/* Start looking for an extended partition in the MBR */
-	while (++part->private.ebr.parent_index < 4) {
-	    uint8_t type = parent_table[part->private.ebr.parent_index].ostype;
-
-	    if ((type == 0x05) || (type == 0x0F) || (type == 0x85))
-		break;
-	}
-	if (part->private.ebr.parent_index == 4)
-	    /* No extended partitions found */
-	    goto out_finished;
-	part->private.ebr.lba_extended =
-	    parent_table[part->private.ebr.parent_index].start_lba;
-	ebr_table = &phony;
-    }
-    /* Load next EBR */
-    ebr_lba = ebr_table->start_lba + part->private.ebr.lba_extended;
-    free(part->block);
-    part->block = disk_read_sectors(&diskinfo, ebr_lba, 1);
-    if (!part->block) {
-	error("Could not load EBR!\n");
-	goto err_ebr;
-    }
-    ebr_table = ((const struct disk_dos_mbr *)part->block)->table;
-    dprintf("next_ebr_part:\n");
-    disk_dos_part_dump(ebr_table);
-
-    /*
-     * Sanity check entry: must not extend outside the
-     * extended partition.  This is necessary since some OSes
-     * put crap in some entries.
-     */
-    {
-	const struct disk_dos_mbr *mbr =
-	    (const struct disk_dos_mbr *)part->private.ebr.parent->block;
-	const struct disk_dos_part_entry *extended =
-	    mbr->table + part->private.ebr.parent_index;
-
-	if (ebr_table[0].start_lba >= extended->start_lba + extended->length) {
-	    dprintf("Insane logical partition!\n");
-	    goto err_insane;
-	}
-    }
-    /* Success */
-    part->lba_data = ebr_table[0].start_lba + ebr_lba;
-    dprintf("Partition %d logical lba %u\n", part->index, part->lba_data);
-    part->index++;
-    part->record = ebr_table;
-    return part;
-
-err_insane:
-
-    free(part->block);
-    part->block = NULL;
-err_ebr:
-
-out_finished:
-    free(part->private.ebr.parent->block);
-    free(part->private.ebr.parent);
-    free(part->block);
-    free(part);
-    return NULL;
-}
-
-static struct disk_part_iter *next_mbr_part(struct disk_part_iter *part)
-{
-    struct disk_part_iter *ebr_part;
-    /* Look at the partition table */
-    struct disk_dos_part_entry *table =
-	((struct disk_dos_mbr *)part->block)->table;
-
-    /* Look for data partitions */
-    while (++part->private.mbr_index < 4) {
-	uint8_t type = table[part->private.mbr_index].ostype;
-
-	if (type == 0x00 || type == 0x05 || type == 0x0F || type == 0x85)
-	    /* Skip empty or extended partitions */
+	/* Check for a MBR disk */
+	boot_part = pi_begin(&diskinfo);
+	if (boot_part->type != typedos) {
+	    pi_del(&boot_part);
 	    continue;
-	if (!table[part->private.mbr_index].length)
-	    /* Empty */
-	    continue;
-	break;
-    }
-    /* If we're currently the last partition, it's time for EBR processing */
-    if (part->private.mbr_index == 4) {
-	/* Allocate another iterator for extended partitions */
-	ebr_part = malloc(sizeof(*ebr_part));
-	if (!ebr_part) {
-	    error("Could not allocate extended partition iterator!\n");
-	    goto err_alloc;
 	}
-	/* Setup EBR iterator parameters */
-	ebr_part->block = NULL;
-	ebr_part->index = 4;
-	ebr_part->record = NULL;
-	ebr_part->next = next_ebr_part;
-	ebr_part->private.ebr.parent = part;
-	/* Trigger an initial EBR load */
-	ebr_part->private.ebr.parent_index = -1;
-	/* The EBR iterator is responsible for freeing us */
-	return next_ebr_part(ebr_part);
-    }
-    dprintf("next_mbr_part:\n");
-    disk_dos_part_dump(table + part->private.mbr_index);
-
-    /* Update parameters to reflect this new partition.  Re-use iterator */
-    part->lba_data = table[part->private.mbr_index].start_lba;
-    dprintf("Partition %d primary lba %u\n", part->private.mbr_index, part->lba_data);
-    part->index = part->private.mbr_index + 1;
-    part->record = table + part->private.mbr_index;
-    return part;
-
-    free(ebr_part);
-err_alloc:
-
-    free(part->block);
-    free(part);
-    return NULL;
-}
-
-static struct disk_part_iter *next_gpt_part(struct disk_part_iter *part)
-{
-    const struct disk_gpt_part_entry *gpt_part = NULL;
-
-    while (++part->private.gpt.index < part->private.gpt.parts) {
-	gpt_part =
-	    (const struct disk_gpt_part_entry *)(part->block +
-						 (part->private.gpt.index *
-						  part->private.gpt.size));
-	if (!gpt_part->lba_first)
-	    continue;
-	break;
-    }
-    /* Were we the last partition? */
-    if (part->private.gpt.index == part->private.gpt.parts) {
-	goto err_last;
-    }
-    part->lba_data = gpt_part->lba_first;
-    part->private.gpt.part_guid = &gpt_part->uid;
-    part->private.gpt.part_label = gpt_part->name;
-    /* Update our index */
-    part->index = part->private.gpt.index + 1;
-#ifdef DEBUG
-    disk_gpt_part_dump(gpt_part);
-#endif
-
-    /* In a GPT scheme, we re-use the iterator */
-    return part;
-
-err_last:
-    free(part->block);
-    free(part);
-
-    return NULL;
-}
-
-static struct disk_part_iter *get_first_partition(struct disk_part_iter *part)
-{
-    const struct disk_gpt_header *gpt_candidate;
-
-    /*
-     * Ignore any passed partition iterator.  The caller should
-     * have passed NULL.  Allocate a new partition iterator
-     */
-    part = malloc(sizeof(*part));
-    if (!part) {
-	error("Count not allocate partition iterator!\n");
-	goto err_alloc_iter;
-    }
-    /* Read MBR */
-    part->block = disk_read_sectors(&diskinfo, 0, 2);
-    if (!part->block) {
-	error("Could not read two sectors!\n");
-	goto err_read_mbr;
-    }
-    /* Check for an MBR */
-    if (((struct disk_dos_mbr *)part->block)->sig != disk_mbr_sig_magic) {
-	error("No MBR magic!\n");
-	goto err_mbr;
-    }
-    /* Establish a pseudo-partition for the MBR (index 0) */
-    part->index = 0;
-    part->record = NULL;
-    part->private.mbr_index = -1;
-    part->next = next_mbr_part;
-    /* Check for a GPT disk */
-    gpt_candidate = (const struct disk_gpt_header *)(part->block + SECTOR);
-    if (!memcmp
-	(gpt_candidate->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) {
-	/* LBA for partition table */
-	uint64_t lba_table;
-
-	/* It looks like one */
-	/* TODO: Check checksum.  Possibly try alternative GPT */
-#if DEBUG
-	puts("Looks like a GPT disk.");
-	disk_gpt_header_dump(gpt_candidate);
-#endif
-	/* TODO: Check table checksum (maybe) */
-	/* Note relevant GPT details */
-	part->next = next_gpt_part;
-	part->private.gpt.index = -1;
-	part->private.gpt.parts = gpt_candidate->part_count;
-	part->private.gpt.size = gpt_candidate->part_size;
-	lba_table = gpt_candidate->lba_table;
-	gpt_candidate = NULL;
-	/* Load the partition table */
-	free(part->block);
-	part->block =
-	    disk_read_sectors(&diskinfo, lba_table,
-			      ((part->private.gpt.size *
-				part->private.gpt.parts) + SECTOR -
-			       1) / SECTOR);
-	if (!part->block) {
-	    error("Could not read GPT partition list!\n");
-	    goto err_gpt_table;
+	if (boot_part->sub.dos.disk_sig == mbr_sig) {
+	    pi_del(&boot_part);
+	    goto ok;
 	}
     }
-    /* Return the pseudo-partition's next partition, which is real */
-    return part->next(part);
-
-err_gpt_table:
-
-err_mbr:
-
-    free(part->block);
-    part->block = NULL;
-err_read_mbr:
-
-    free(part);
-err_alloc_iter:
-
-    return NULL;
+    drive = -1;
+ok:
+    return drive;
 }
 
 /*
@@ -472,45 +182,35 @@ err_alloc_iter:
  * found, we return -1.
  */
 static int find_by_guid(const struct guid *gpt_guid,
-			struct disk_part_iter **boot_part)
+			struct part_iter **_boot_part)
 {
+    struct part_iter *boot_part = NULL;
     int drive;
-    bool is_me;
-    struct disk_gpt_header *header;
 
     for (drive = 0x80; drive <= 0xff; drive++) {
 	if (disk_get_params(drive, &diskinfo))
 	    continue;		/* Drive doesn't exist */
-	if (!(header = disk_read_sectors(&diskinfo, 1, 1)))
-	    continue;		/* Cannot read sector */
-	if (memcmp
-	    (&header->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) {
-	    /* Not a GPT disk */
-	    free(header);
+	/* Check for a GPT disk */
+	boot_part = pi_begin(&diskinfo);
+	if (boot_part->type != typegpt) {
+	    pi_del(&boot_part);
 	    continue;
 	}
-#if DEBUG
-	disk_gpt_header_dump(header);
-#endif
-	is_me = !memcmp(&header->disk_guid, &gpt_guid, sizeof(*gpt_guid));
-	free(header);
-	if (!is_me) {
-	    /* Check for a matching partition */
-	    boot_part[0] = get_first_partition(NULL);
-	    while (boot_part[0]) {
-		is_me =
-		    !memcmp(boot_part[0]->private.gpt.part_guid, gpt_guid,
-			    sizeof(*gpt_guid));
-		if (is_me)
-		    break;
-		boot_part[0] = boot_part[0]->next(boot_part[0]);
-	    }
-	} else
-	    boot_part[0] = NULL;
-	if (is_me)
-	    return drive;
+	/* Check for a matching GPT disk guid */
+	if(!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
+	    pi_del(&boot_part);
+	    goto ok;
+	}
+	/* disk guid doesn't match, maybe partition guid will */
+	while (pi_next(&boot_part)) {
+	    if(!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
+		goto ok;
+	}
     }
-    return -1;
+    drive = -1;
+ok:
+    *_boot_part = boot_part;
+    return drive;
 }
 
 /*
@@ -520,47 +220,30 @@ static int find_by_guid(const struct guid *gpt_guid,
  * If no matching partition is found, boot_part will be populated with
  * NULL and we return -1.
  */
-static int find_by_label(const char *label, struct disk_part_iter **boot_part)
+static int find_by_label(const char *label, struct part_iter **_boot_part)
 {
+    struct part_iter *boot_part = NULL;
     int drive;
-    bool is_me;
 
     for (drive = 0x80; drive <= 0xff; drive++) {
 	if (disk_get_params(drive, &diskinfo))
 	    continue;		/* Drive doesn't exist */
 	/* Check for a GPT disk */
-	boot_part[0] = get_first_partition(NULL);
-	if (!(boot_part[0]->next == next_gpt_part)) {
-	    /* Not a GPT disk */
-	    while (boot_part[0]) {
-		/* Run through until the end */
-		boot_part[0] = boot_part[0]->next(boot_part[0]);
-	    }
+	boot_part = pi_begin(&diskinfo);
+	if (!(boot_part->type == typegpt)) {
+	    pi_del(&boot_part);
 	    continue;
 	}
 	/* Check for a matching partition */
-	while (boot_part[0]) {
-	    char gpt_label[sizeof(((struct disk_gpt_part_entry *) NULL)->name)];
-	    const char *gpt_label_scanner =
-		boot_part[0]->private.gpt.part_label;
-	    int j = 0;
-
-	    /* Re-write the GPT partition label as ASCII */
-	    while (gpt_label_scanner <
-		   boot_part[0]->private.gpt.part_label + sizeof(gpt_label)) {
-		if ((gpt_label[j] = *gpt_label_scanner))
-		    j++;
-		gpt_label_scanner++;
-	    }
-	    if ((is_me = !strcmp(label, gpt_label)))
-		break;
-	    boot_part[0] = boot_part[0]->next(boot_part[0]);
+	while (pi_next(&boot_part)) {
+	    if (!strcmp(label, boot_part->sub.gpt.part_label))
+		goto ok;
 	}
-	if (is_me)
-	    return drive;
     }
-
-    return -1;
+    drive = -1;
+ok:
+    *_boot_part = boot_part;
+    return drive;
 }
 
 static void do_boot(struct data_area *data, int ndata,
@@ -698,10 +381,8 @@ static int hide_unhide(struct disk_dos_mbr *mbr, int part)
     int i;
     struct disk_dos_part_entry *pt;
     const uint16_t mask =
-	(1 << 0x01) | (1 << 0x04) | (1 << 0x06) | (1 << 0x07) | (1 << 0x0b) | (1
-									       <<
-									       0x0c)
-	| (1 << 0x0e);
+	(1 << 0x01) | (1 << 0x04) | (1 << 0x06) |
+	(1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e);
     uint8_t t;
     bool write_back = false;
 
@@ -802,7 +483,12 @@ int main(int argc, char *argv[])
 {
     struct disk_dos_mbr *mbr = NULL;
     char *p;
-    struct disk_part_iter *cur_part = NULL;
+    struct part_iter *cur_part = NULL;
+
+    void *sect_area = NULL;
+    void *file_area = NULL;
+    struct disk_dos_part_entry *hand_area = NULL;
+
     struct syslinux_rm_regs regs;
     char *drivename, *partition;
     int hd, drive, whichpart = 0;	/* MBR by default */
@@ -918,7 +604,7 @@ int main(int argc, char *argv[])
 
     hd = 0;
     if (!strncmp(drivename, "mbr", 3)) {
-	drive = find_disk(strtoul(drivename + 4, NULL, 0));
+	drive = find_by_sig(strtoul(drivename + 4, NULL, 0));
 	if (drive == -1) {
 	    error("Unable to find requested MBR signature\n");
 	    goto bail;
@@ -982,33 +668,45 @@ int main(int argc, char *argv[])
 
     if (partition)
 	whichpart = strtoul(partition, NULL, 0);
-    /* "guid:" or "label:" might have specified a partition */
+
+    /* "guid:" or "label:" might have specified a partition. In such case,
+     * this overrides explicit partition number specification. cur-part->index
+     * can't be 0 at this stage as find_by* won't export iterator at such
+     * position.
+     */
     if (cur_part)
 	whichpart = cur_part->index;
 
-    /* Boot the MBR by default */
-    if (!cur_part && (whichpart || fs_lba)) {
-	/* Boot a partition, possibly the Syslinux partition itself */
-	cur_part = get_first_partition(NULL);
-	while (cur_part) {
-	    if ((cur_part->index == whichpart)
-		|| (cur_part->lba_data == fs_lba))
-		/* Found the partition to boot */
+    /* If nothing was found, try fs/boot first */
+    if (!cur_part && fs_lba) {
+	cur_part = pi_begin(&diskinfo);
+	/* search for matching fs_lba, must be partition */
+	while (pi_next(&cur_part)) {
+	    if (cur_part->start_lba == fs_lba)
 		break;
-	    cur_part = cur_part->next(cur_part);
-	}
-	if (!cur_part) {
-	    error("Requested partition not found!\n");
-	    goto bail;
 	}
-	whichpart = cur_part->index;
     }
+    /* If still nothing found, do standard search */
+    if (!cur_part) {
+	cur_part = pi_begin(&diskinfo);
+	/* search for matching part#, including disk */
+	do {
+	    if (cur_part->index == whichpart)
+		break;
+	} while (pi_next(&cur_part));
+    }
+    if (!cur_part) {
+	error("Requested disk / partition not found!\n");
+	goto bail;
+    }
+
+    whichpart = cur_part->index;
 
     if (!(drive & 0x80) && whichpart) {
 	error("Warning: Partitions of floppy devices may not work\n");
     }
 
-    /* 
+    /*
      * GRLDR of GRUB4DOS wants the partition number in DH:
      * -1:   whole drive (default)
      * 0-3:  primary partitions
@@ -1034,6 +732,7 @@ int main(int argc, char *argv[])
 	    goto bail;
 	}
 	data[ndata].base = load_base;
+	file_area = (void *)data[ndata].data;
 	load_base = 0x7c00;	/* If we also load a boot sector */
 
 	/* Create boot info table: needed when you want to chainload
@@ -1058,7 +757,7 @@ int main(int argc, char *argv[])
 		   boot file starting at byte offset 64. All linear block
 		   addresses (LBAs) are given in CD sectors (normally 2048 bytes).
 
-		   LBA of primary volume descriptor should already be set to 16. 
+		   LBA of primary volume descriptor should already be set to 16.
 		 */
 
 		isolinux_bin = (unsigned char *)data[ndata].data;
@@ -1176,7 +875,7 @@ int main(int argc, char *argv[])
 	     * another location.
 	     *
 	     * Partition numbers always start from zero.
-	     * Unused partition bytes must be set to 0xFF. 
+	     * Unused partition bytes must be set to 0xFF.
 	     *
 	     * We only care about top-level partition, so we only need to change
 	     * "part1" to the appropriate value:
@@ -1207,15 +906,15 @@ int main(int argc, char *argv[])
 
     if (!opt.loadfile || data[0].base >= 0x7c00 + SECTOR) {
 	/* Actually read the boot sector */
-	if (!cur_part) {
+	if (!cur_part->index) {
 	    data[ndata].data = mbr;
 	} else
-	    if (!
-		(data[ndata].data =
-		 disk_read_sectors(&diskinfo, cur_part->lba_data, 1))) {
+	    if (!(data[ndata].data =
+		 disk_read_sectors(&diskinfo, cur_part->start_lba, 1))) {
 	    error("Cannot read boot sector\n");
 	    goto bail;
-	}
+	} else
+	    sect_area = (void *)data[ndata].data;
 	data[ndata].size = SECTOR;
 	data[ndata].base = load_base;
 
@@ -1235,7 +934,7 @@ int main(int argc, char *argv[])
 	 * the string "cmdcons\0" to memory location 0000:7C03.
 	 * Memory location 0000:7C00 contains the bootsector of the partition.
 	 */
-	if (cur_part && opt.cmldr) {
+	if (cur_part->index && opt.cmldr) {
 	    memcpy((char *)data[ndata].data + 3, cmldr_signature,
 		   sizeof cmldr_signature);
 	}
@@ -1245,94 +944,97 @@ int main(int argc, char *argv[])
 	 * this modifies the field used by FAT and NTFS filesystems, and
 	 * possibly other boot loaders which use the same format.
 	 */
-	if (cur_part && opt.sethidden) {
-	    *(uint32_t *) ((char *)data[ndata].data + 28) = cur_part->lba_data;
+	if (cur_part->index && opt.sethidden) {
+	    *(uint32_t *) ((char *)data[ndata].data + 28) = cur_part->start_lba;
 	}
 
 	ndata++;
     }
 
-    if (cur_part) {
-	if (cur_part->next == next_gpt_part) {
+    if (cur_part->index) {
+	if (cur_part->type == typegpt) {
 	    /* Do GPT hand-over, if applicable (as per syslinux/doc/gpt.txt) */
-	    struct disk_dos_part_entry *record;
 	    /* Look at the GPT partition */
 	    const struct disk_gpt_part_entry *gp =
-		(const struct disk_gpt_part_entry *)
-		(cur_part->block +
-		 (cur_part->private.gpt.size * cur_part->private.gpt.index));
+		(const struct disk_gpt_part_entry *)cur_part->record;
 	    /* Note the partition length */
 	    uint64_t lba_count = gp->lba_last - gp->lba_first + 1;
 	    /* The length of the hand-over */
-	    int synth_size =
+	    uint32_t synth_size =
 		sizeof(struct disk_dos_part_entry) + sizeof(uint32_t) +
-		cur_part->private.gpt.size;
+		cur_part->sub.gpt.pe_size;
 	    /* Will point to the partition record length in the hand-over */
 	    uint32_t *plen;
 
 	    /* Allocate the hand-over record */
-	    record = malloc(synth_size);
-	    if (!record) {
+	    hand_area = malloc(synth_size);
+	    if (!hand_area) {
 		error("Could not build GPT hand-over record!\n");
 		goto bail;
 	    }
 	    /* Synthesize the record */
-	    memset(record, 0, synth_size);
-	    record->active_flag = 0x80;
-	    record->ostype = 0xED;
+	    memset(hand_area, 0, synth_size);
+	    hand_area->active_flag = 0x80;
+	    hand_area->ostype = 0xED;
 	    /* All bits set by default */
-	    record->start_lba = ~(uint32_t) 0;
-	    record->length = ~(uint32_t) 0;
+	    hand_area->start_lba = ~(uint32_t) 0;
+	    hand_area->length = ~(uint32_t) 0;
 	    /* If these fit the precision, pass them on */
-	    if (cur_part->lba_data < record->start_lba)
-		record->start_lba = cur_part->lba_data;
-	    if (lba_count < record->length)
-		record->length = lba_count;
+	    if (cur_part->start_lba < hand_area->start_lba)
+		hand_area->start_lba = cur_part->start_lba;
+	    if (lba_count < hand_area->length)
+		hand_area->length = lba_count;
 	    /* Next comes the GPT partition record length */
-	    plen = (uint32_t *) (record + 1);
-	    plen[0] = cur_part->private.gpt.size;
+	    plen = (uint32_t *) (hand_area + 1);
+	    plen[0] = cur_part->sub.gpt.pe_size;
 	    /* Next comes the GPT partition record copy */
 	    memcpy(plen + 1, gp, plen[0]);
-	    cur_part->record = record;
 
 	    regs.eax.l = 0x54504721;	/* '!GPT' */
 	    data[ndata].base = 0x7be;
 	    data[ndata].size = synth_size;
-	    data[ndata].data = (void *)record;
+	    data[ndata].data = (void *)hand_area;
 	    ndata++;
 	    regs.esi.w[0] = 0x7be;
-
-	    dprintf("GPT handover:\n");
-	    disk_dos_part_dump(record);
 #ifdef DEBUG
+	    dprintf("GPT handover:\n");
+	    disk_dos_part_dump(hand_area);
 	    disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1));
 #endif
-	} else if (cur_part->record) {
+	} else {
 	    /* MBR handover protocol */
-	    static struct disk_dos_part_entry handover_record;
+	    /* Allocate the hand-over record */
+	    hand_area = malloc(sizeof(struct disk_dos_part_entry));
+	    if (!hand_area) {
+		error("Could not build MBR hand-over record!\n");
+		goto bail;
+	    }
 
-	    handover_record = *cur_part->record;
-	    handover_record.start_lba = cur_part->lba_data;
+	    memcpy(hand_area, cur_part->record, sizeof(struct disk_dos_part_entry));
+	    hand_area->start_lba = cur_part->start_lba;
 
 	    data[ndata].base = 0x7be;
-	    data[ndata].size = sizeof handover_record;
-	    data[ndata].data = &handover_record;
+	    data[ndata].size = sizeof(struct disk_dos_part_entry);
+	    data[ndata].data = (void *)hand_area;
 	    ndata++;
 	    regs.esi.w[0] = 0x7be;
-
+#ifdef DEBUG
 	    dprintf("MBR handover:\n");
-	    disk_dos_part_dump(&handover_record);
+	    disk_dos_part_dump(hand_area);
+#endif
 	}
     }
 
     do_boot(data, ndata, &regs);
 
 bail:
-    if (cur_part) {
-	free(cur_part->block);
-	free((void *)cur_part->record);
-    }
-    free(cur_part);
+    pi_del(&cur_part);
+    /* Free allocated areas */
     free(mbr);
+    free(file_area);
+    free(sect_area);
+    free(hand_area);
     return 255;
 }
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
new file mode 100644
index 0000000..4b76e22
--- /dev/null
+++ b/com32/chain/partiter.c
@@ -0,0 +1,714 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.c
+ *
+ * Provides disk / partition iteration.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <zlib.h>
+#include <syslinux/disk.h>
+#include "partiter.h"
+
+#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
+#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
+#define sane(s,l) ((s)+(l) > (s))
+
+/* this is chosen to follow how many sectors disklib can read at once */
+#define MAXGPTPTSIZE (255u*SECTOR)
+
+static void error(const char *msg)
+{
+    fputs(msg, stderr);
+}
+
+/* forwards */
+
+static int iter_dos_ctor(struct part_iter *, va_list *);
+static int iter_gpt_ctor(struct part_iter *, va_list *);
+static void iter_dtor(struct part_iter *);
+static struct part_iter *pi_dos_next(struct part_iter *);
+static struct part_iter *pi_gpt_next(struct part_iter *);
+
+static struct itertype types[] = {
+   [0] = {
+	.ctor = &iter_dos_ctor,
+	.dtor = &iter_dtor,
+	.next = &pi_dos_next,
+}, [1] = {
+	.ctor = &iter_gpt_ctor,
+	.dtor = &iter_dtor,
+	.next = &pi_gpt_next,
+}};
+
+const struct itertype * const typedos = types;
+const struct itertype * const typegpt = types+1;
+
+static int inv_type(const void *type)
+{
+    int i, cnt = sizeof(types)/sizeof(types[0]);
+    for (i = 0; i < cnt; i++) {
+	if (type == types + i)
+	    return 0;
+    }
+    return -1;
+}
+
+static int guid_is0(const struct guid *guid)
+{
+    return !*(const uint64_t *)guid && !*((const uint64_t *)guid+1);
+}
+
+/**
+ * iter_ctor() - common iterator initialization
+ * @iter:	iterator pointer
+ * @args(0):	disk_info structure used for disk functions
+ *
+ * Second and further arguments are passed as a pointer to va_list
+ **/
+static int iter_ctor(struct part_iter *iter, va_list *args)
+{
+    const struct disk_info *di = va_arg(*args, const struct disk_info *);
+
+    if (!di)
+	return -1;
+
+    memcpy(&iter->di, di, sizeof(struct disk_info));
+
+    return 0;
+}
+
+/**
+ * iter_dtor() - common iterator cleanup
+ * @iter:	iterator pointer
+ *
+ **/
+static void iter_dtor(struct part_iter *iter)
+{
+    free(iter->data);
+}
+
+/**
+ * iter_dos_ctor() - MBR/EBR iterator specific initialization
+ * @iter:	iterator pointer
+ * @args(0):	disk_info structure used for disk functions
+ * @args(1):	pointer to buffer with loaded valid MBR
+ *
+ * Second and further arguments are passed as a pointer to va_list.
+ * This function only makes rudimentary checks. If user uses
+ * pi_new(), he/she is responsible for doing proper sanity checks.
+ **/
+static int iter_dos_ctor(struct part_iter *iter, va_list *args)
+{
+    const struct disk_dos_mbr *mbr;
+
+    /* uses args(0) */
+    if (iter_ctor(iter, args))
+	return -1;
+
+    mbr = va_arg(*args, const struct disk_dos_mbr *);
+
+    if (!mbr)
+	goto out;
+
+    if (!(iter->data = malloc(sizeof(struct disk_dos_mbr))))
+	goto out;
+
+    memcpy(iter->data, mbr, sizeof(struct disk_dos_mbr));
+
+    iter->sub.dos.index0 = -1;
+    iter->sub.dos.bebr_index0 = -1;
+    iter->sub.dos.disk_sig = mbr->disk_sig;
+
+    return 0;
+out:
+    iter->type->dtor(iter);
+    return -1;
+}
+
+/**
+ * iter_gpt_ctor() - GPT iterator specific initialization
+ * @iter:	iterator pointer
+ * @args(0):	ptr to disk_info structure
+ * @args(1):	ptr to buffer with GPT header
+ * @args(2):	ptr to buffer with GPT partition list
+ *
+ * Second and further arguments are passed as a pointer to va_list.
+ * This function only makes rudimentary checks. If user uses
+ * pi_new(), he/she is responsible for doing proper sanity checks.
+ **/
+static int iter_gpt_ctor(struct part_iter *iter, va_list *args)
+{
+    uint64_t siz;
+    const struct disk_gpt_header *gpth;
+    const struct disk_gpt_part_entry *gptl;
+
+    /* uses args(0) */
+    if (iter_ctor(iter, args))
+	return -1;
+
+    gpth = va_arg(*args, const struct disk_gpt_header *);
+    gptl = va_arg(*args, const struct disk_gpt_part_entry *);
+
+    if (!gpth || !gptl)
+	goto out;
+
+    siz = (uint64_t)gpth->part_count * (uint64_t)gpth->part_size;
+
+    if (!siz || siz > MAXGPTPTSIZE ||
+	    gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+	goto out;
+    }
+
+    if (!(iter->data = malloc((size_t)siz)))
+	goto out;
+
+    memcpy(iter->data, gptl, (size_t)siz);
+
+    iter->sub.gpt.index0 = -1;
+    iter->sub.gpt.pe_count = (int)gpth->part_count;
+    iter->sub.gpt.pe_size = (int)gpth->part_size;
+    memcpy(&iter->sub.gpt.disk_guid, &gpth->disk_guid, sizeof(struct guid));
+
+    return 0;
+
+out:
+    iter->type->dtor(iter);
+    return -1;
+}
+
+/* Logical partition must be sane, meaning:
+ * - must be data or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside current EBR frame
+ */
+
+static int notsane_logical(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    uint32_t end_log;
+
+    dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+    if (!dp[0].ostype)
+	return 0;
+
+    if (ost_is_ext(dp[0].ostype)) {
+	error("1st EBR entry must be data or empty.\n");
+	return -1;
+    }
+
+    end_log = dp[0].start_lba + dp[0].length;
+
+    if (!dp[0].start_lba ||
+	!dp[0].length ||
+	!sane(dp[0].start_lba, dp[0].length) ||
+	end_log > iter->sub.dos.ebr_size) {
+
+	error("Insane logical partition.\n");
+	return -1;
+    }
+
+    return 0;
+}
+
+/* Extended partition must be sane, meaning:
+ * - must be extended or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside base EBR frame
+ */
+
+static int notsane_extended(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    uint32_t end_ebr;
+
+    dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+    if (!dp[1].ostype)
+	return 0;
+
+    if (!ost_is_nondata(dp[1].ostype)) {
+	error("2nd EBR entry must be extended or empty.\n");
+	return -1;
+    }
+
+    end_ebr = dp[1].start_lba + dp[1].length;
+
+    if (!dp[1].start_lba ||
+	!dp[1].length ||
+	!sane(dp[1].start_lba, dp[1].length) ||
+	end_ebr > iter->sub.dos.bebr_size) {
+
+	error("Insane extended partition.\n");
+	return -1;
+    }
+
+    return 0;
+}
+
+/* Primary partition must be sane, meaning:
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ */
+
+static int notsane_primary(const struct disk_dos_part_entry *dp)
+{
+    if (!dp->ostype)
+	return 0;
+
+    if (!dp->start_lba ||
+	!dp->length ||
+	!sane(dp->start_lba, dp->length)) {
+	error("Insane primary (MBR) partition.\n");
+	return -1;
+    }
+
+    return 0;
+}
+
+static int notsane_gpt(const struct disk_gpt_part_entry *gp)
+{
+    if (guid_is0(&gp->type))
+	return 0;
+
+    if (!gp->lba_first ||
+	!gp->lba_last ||
+	gp->lba_first > gp->lba_last) {
+	error("Insane GPT partition.\n");
+	return -1;
+    }
+
+    return 0;
+}
+
+static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
+			    struct disk_dos_part_entry **_dp)
+{
+    struct disk_dos_part_entry *dp;
+
+    while (++iter->sub.dos.index0 < 4) {
+	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.index0;
+
+	if (notsane_primary(dp))
+	    return -1;
+
+	if (ost_is_ext(dp->ostype)) {
+	    if (iter->sub.dos.bebr_index0 >= 0) {
+		error("You have more than 1 extended partition.\n");
+		return -1;
+	    }
+	    /* record base EBR index */
+	    iter->sub.dos.bebr_index0 = iter->sub.dos.index0;
+	}
+	if (ost_is_nondata(dp->ostype))
+	    continue;
+
+	break;
+    }
+
+    *lba = dp->start_lba;
+    *_dp = dp;
+    return 0;
+}
+
+static int prep_base_ebr(struct part_iter *iter)
+{
+    struct disk_dos_part_entry *dp;
+
+    if (iter->sub.dos.bebr_index0 < 0)
+	return -1;
+    else if (!iter->sub.dos.bebr_start) {
+	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.bebr_index0;
+
+	iter->sub.dos.bebr_start = dp->start_lba;
+	iter->sub.dos.bebr_size = dp->length;
+
+	iter->sub.dos.ebr_start = 0;
+	iter->sub.dos.ebr_size = iter->sub.dos.bebr_size;
+
+	iter->sub.dos.index0--;
+    }
+    return 0;
+}
+
+static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
+			    struct disk_dos_part_entry **_dp)
+{
+    struct disk_dos_part_entry *dp;
+    uint32_t abs_ebr;
+
+    if (prep_base_ebr(iter))
+	return -1;
+
+    if(++iter->sub.dos.index0 >= 1024)
+	/* that's one paranoid upper bound */
+	return -1;
+
+    while (iter->sub.dos.ebr_size) {
+
+	abs_ebr = iter->sub.dos.bebr_start + iter->sub.dos.ebr_start;
+
+	/* load ebr for current iteration */
+	free(iter->data);
+	if (!(iter->data = disk_read_sectors(&iter->di, abs_ebr, 1))) {
+	    error("Couldn't load EBR.\n");
+	    break;
+	}
+
+	if (notsane_logical(iter) || notsane_extended(iter))
+	    break;
+
+	dp = ((struct disk_dos_mbr *)iter->data)->table;
+	abs_ebr += dp[0].start_lba;
+
+	/* setup next frame values */
+	if (dp[1].ostype) {
+	    iter->sub.dos.ebr_start = dp[1].start_lba;
+	    iter->sub.dos.ebr_size = dp[1].length;
+	} else {
+	    iter->sub.dos.ebr_size = 0;
+	}
+
+	if (dp[0].ostype) {
+	    *lba = abs_ebr;
+	    *_dp = dp;
+	    return 0;
+	}
+	/*
+	 * This way it's possible to continue, if some crazy soft left a "hole"
+	 * - EBR with a valid extended partition without a logical one. In
+	 * such case, linux will not reserve a number for such hole - so we
+	 * don't increase index0.
+	 */
+    }
+    return -1;
+}
+
+static struct part_iter *pi_dos_next(struct part_iter *iter)
+{
+    uint32_t start_lba = 0;
+    struct disk_dos_part_entry *dos_part = NULL;
+
+    /* look for primary partitions */
+    if (iter->sub.dos.index0 < 4 &&
+	    pi_dos_next_mbr(iter, &start_lba, &dos_part))
+        return pi_del(&iter);
+
+    /* look for logical partitions */
+    if (iter->sub.dos.index0 >= 4 &&
+	    pi_dos_next_ebr(iter, &start_lba, &dos_part))
+	return pi_del(&iter);
+
+    /* dos_part and start_lba are guaranteed to be valid here */
+
+    iter->index = iter->sub.dos.index0 + 1;
+    iter->start_lba = start_lba;
+    iter->record = (char *)dos_part;
+
+#ifdef DEBUG
+    disk_dos_part_dump(dos_part);
+#endif
+
+    return iter;
+}
+
+static void gpt_conv_label(struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gp;
+    const int16_t *orig_lab;
+
+    gp = (const struct disk_gpt_part_entry *)
+	(iter->data + iter->sub.gpt.index0 * iter->sub.gpt.pe_size);
+    orig_lab = (const int16_t *)gp->name;
+
+    /* caveat: this is very crude conversion */
+    for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
+	iter->sub.gpt.part_label[i] = (char)orig_lab[i];
+    }
+    iter->sub.gpt.part_label[PI_GPTLABSIZE/2] = 0;
+}
+
+static struct part_iter *pi_gpt_next(struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gpt_part = NULL;
+
+    while (++iter->sub.gpt.index0 < iter->sub.gpt.pe_count) {
+	gpt_part = (const struct disk_gpt_part_entry *)
+	    (iter->data + iter->sub.gpt.index0 * iter->sub.gpt.pe_size);
+
+	if (notsane_gpt(gpt_part))
+	    goto out;
+
+	if (guid_is0(&gpt_part->type))
+	    continue;
+	break;
+    }
+    /* no more partitions ? */
+    if (iter->sub.gpt.index0 == iter->sub.gpt.pe_count) {
+	goto out;
+    }
+    /* gpt_part is guaranteed to be valid here */
+    iter->index = iter->sub.gpt.index0 + 1;
+    iter->start_lba = gpt_part->lba_first;
+    iter->record = (char *)gpt_part;
+    memcpy(&iter->sub.gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
+    gpt_conv_label(iter);
+
+#ifdef DEBUG
+    disk_gpt_part_dump(gpt_part);
+#endif
+
+    return iter;
+out:
+    return pi_del(&iter);
+}
+
+static int check_crc(uint32_t crc_match, const uint8_t *buf, unsigned int siz)
+{
+    uint32_t crc;
+
+    crc = crc32(0, NULL, 0);
+    crc = crc32(crc, buf, siz);
+
+    return crc_match != crc;
+}
+
+static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh)
+{
+    struct disk_gpt_header *gh = *_gh;
+    uint64_t lba_alt;
+    uint32_t hold_crc32;
+
+    hold_crc32 = gh->chksum;
+    gh->chksum = 0;
+    if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+	error("WARNING: Primary GPT header checksum invalid.\n");
+	/* retry with backup */
+	lba_alt = gh->lba_alt;
+	free(gh);
+	if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) {
+	    error("Couldn't read backup GPT header.\n");
+	    return -1;
+	}
+	hold_crc32 = gh->chksum;
+	gh->chksum = 0;
+	if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+	    error("Secondary GPT header checksum invalid.\n");
+	    return -1;
+	}
+    }
+    /* restore old checksum */
+    gh->chksum = hold_crc32;
+
+    return 0;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Following functions are for users to call.
+ * ----------------------------------------------------------------------------
+ */
+
+
+struct part_iter *pi_next(struct part_iter **_iter)
+{
+    struct part_iter *iter = *_iter;
+    if (!iter)
+	return NULL;
+    if (inv_type(iter->type)) {
+	error("This is not a valid iterator.\n");
+	return NULL;
+    }
+    *_iter = iter->type->next(iter);
+    return *_iter;
+}
+
+/**
+ * pi_new() - get new iterator
+ * @itertype:	iterator type
+ * @...:	variable arguments passed to ctors
+ *
+ * Variable arguments depend on the type. Please see functions:
+ * iter_gpt_ctor() and iter_dos_ctor() for details.
+ **/
+struct part_iter *pi_new(const struct itertype *type, ...)
+{
+    int badctor = 0;
+    struct part_iter *iter = NULL;
+    va_list ap;
+
+    if (inv_type(type)) {
+	error("Unknown iterator requested.\n");
+	return NULL;
+    }
+
+    if (!(iter = malloc(sizeof(struct part_iter)))) {
+	error("Couldn't allocate memory for the iterator.\n");
+	return NULL;
+    }
+
+    memset(iter, 0, sizeof(struct part_iter));
+    iter->type = type;
+
+    va_start(ap, type);
+
+    if ((badctor = type->ctor(iter, &ap))) {
+	error("Cannot initialize the iterator.\n");
+	goto out;
+    }
+
+out:
+    va_end(ap);
+    if (badctor) {
+	free(iter);
+	iter = NULL;
+    }
+    return iter;
+}
+
+/**
+ * pi_del() - delete iterator
+ * @iter:       iterator double pointer
+ *
+ **/
+
+void *pi_del(struct part_iter **_iter)
+{
+    struct part_iter *iter;
+
+    if(!_iter || !*_iter)
+	return NULL;
+    iter = *_iter;
+
+    if (inv_type(iter->type)) {
+	error("This is not a valid iterator.\n");
+	return NULL;
+    }
+    iter->type->dtor(iter);
+    free(iter);
+    *_iter = NULL;
+    return NULL;
+}
+
+/**
+ * pi_begin() - check disk, validate, and get proper iterator
+ * @di:	    diskinfo struct pointer
+ *
+ * This function checks the disk for GPT or legacy partition table and allocates
+ * an appropriate iterator.
+ **/
+struct part_iter *pi_begin(const struct disk_info *di)
+{
+    struct part_iter *iter = NULL;
+    struct disk_dos_mbr *mbr = NULL;
+    struct disk_gpt_header *gpth = NULL;
+    struct disk_gpt_part_entry *gptl = NULL;
+
+    /* Read MBR */
+    if (!(mbr = disk_read_sectors(di, 0, 1))) {
+	error("Couldn't read MBR sector.");
+	goto out;
+    }
+
+    /* Check for MBR magic*/
+    if (mbr->sig != disk_mbr_sig_magic) {
+	error("No MBR magic.\n");
+	goto out;
+    }
+
+    /* Check for GPT protective MBR */
+    if (mbr->table[0].ostype == 0xEE) {
+	if (!(gpth = disk_read_sectors(di, 1, 1))) {
+	    error("Couldn't read GPT header.");
+	    goto out;
+	}
+    }
+
+    if (gpth && gpth->rev.uint32 == 0x00010000 &&
+	    !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) {
+	/* looks like GPT v1.0 */
+	uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
+	uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
+#if DEBUG
+	puts("Looks like a GPT v1.0 disk.");
+	disk_gpt_header_dump(gpth);
+#endif
+	/* Verify checksum, fallback to backup, then bail if invalid */
+	if (gpt_check_hdr_crc(di, &gpth))
+	    goto out;
+
+	gpt_loff = gpth->lba_table;
+	gpt_lsiz = (uint64_t)gpth->part_size*gpth->part_count;
+
+	/*
+	 * disk_read_sectors allows reading of max 255 sectors, so we use
+	 * it as a sanity check base. EFI doesn't specify max.
+	 */
+	if (!gpt_loff || !gpt_lsiz || gpt_lsiz > MAXGPTPTSIZE ||
+		gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+	    error("Invalid GPT header's lba_table/part_count/part_size values.\n");
+	    goto out;
+	}
+	if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)((gpt_lsiz+SECTOR-1)/SECTOR)))) {
+	    error("Couldn't read GPT partition list.\n");
+	    goto out;
+	}
+	/* Check array checksum. */
+	if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+	    error("GPT partition list checksum invalid.\n");
+	    goto out;
+	}
+	/* allocate iterator and exit */
+	if (!(iter = pi_new(typegpt, di, gpth, gptl)))
+	    goto out;
+    } else {
+	/* looks like MBR */
+	if (!(iter = pi_new(typedos, di, mbr)))
+	    goto out;
+    }
+
+    /* we do not do first iteration ! */
+
+out:
+    free(mbr);
+    free(gpth);
+    free(gptl);
+
+    return iter;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
new file mode 100644
index 0000000..c2bbb44
--- /dev/null
+++ b/com32/chain/partiter.h
@@ -0,0 +1,94 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.h
+ *
+ * Provides disk / partition iteration.
+ */
+
+#ifndef _SYSLINUX_PARTITER_H
+#define _SYSLINUX_PARTITER_H
+
+#include <stdint.h>
+#include <syslinux/disk.h>
+
+struct itertype;
+struct part_iter;
+
+struct itertype {
+	int (*ctor)(struct part_iter *, va_list *);
+	void (*dtor)(struct part_iter *);
+	struct part_iter *(*next) (struct part_iter *);
+};
+
+#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
+
+struct part_iter {
+    const struct itertype *type;
+    char *record;
+    uint64_t start_lba;
+    int index;
+    /* internal */
+    char *data;
+    struct disk_info di;
+    union _sub {
+	struct _dos {
+	    uint32_t disk_sig;
+	    /* internal */
+	    uint32_t ebr_start;
+	    uint32_t ebr_size;
+	    uint32_t bebr_start;
+	    uint32_t bebr_size;
+	    int index0;
+	    int bebr_index0;
+	} dos;
+	struct _gpt {
+	    struct guid disk_guid;
+	    struct guid part_guid;
+	    char part_label[PI_GPTLABSIZE/2+1];
+	    /* internal */
+	    int pe_count;
+	    int pe_size;
+	    int index0;
+	} gpt;
+    } sub;
+};
+
+extern const struct itertype * const typedos;
+extern const struct itertype * const typegpt;
+
+struct part_iter *pi_begin(const struct disk_info *);
+struct part_iter *pi_new(const struct itertype *, ...);
+void *pi_del(struct part_iter **);
+struct part_iter *pi_next(struct part_iter **);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 2d47913..e1b62b5 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -18,7 +18,7 @@
 topdir = ../..
 include ../MCONFIG
 
-MODULES	  = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
+MODULES	  = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
 	    disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \
 	    meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \
 	    kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \
-- 
1.7.2.1




More information about the Syslinux mailing list